Casting between C++ method pointers with identical parameters and compatible return values

Viewed 86

Suppose you have these classes:

class A {};
class B : public A {};
class C : public A {};

class Gen {
public: 
     A* genA(int val);
     B* genB(int val);
     C* genC(int val);
};
    

With these I can do this:

Gen g;
A* a = g.genA(1);
A* b = g.genB(1);
A* c = g.genC(1);

Now, suppose I want to pass the generating function around to avoid having to build an enum and table or some other layer of indirection. (And also suppose that because didn't write Gen I can't just change the return types.) Then I would want something like this typedef:

typedef A* (Gen::*GenMethod)(int);

Unfortunately you can't directly assign &Gen::genB or &Gen::genC to a pointer of that type, nor can you use a static_cast<> to cast it to that type.

You can, however, use a reinterpret_cast<>, which isn't surprising because reinterpret_cast<> lets you do all sorts of things.

In my testing the code using the reinterpret_cast<> for this case works fine. So my questions are:

  1. Is there a better/more specific way of doing this (without building a layer of indirection), and
  2. If not, is this one of those rare cases where a reinterpret_cast<> can be used safely?
1 Answers

You can store these covariant member function pointers in a std::function:

std::function<A*(Gen&, int)> dispatch(&Gen::genB);

and then call it like this:

Gen g;
A* b = dispatch(g, 1);

This works because the return types of the callables stored in a std::function need only be convertible to the type given in the template argument (A *), and need not be exactly of that type. In this example, B * is convertibel to A *.

Related