I’m using a library that defines an interface:
template<class desttype>
void connect(desttype* pclass, void (desttype::*pmemfun)());
and I have a small hierarchy
class base {
void foo();
};
class derived: public base { ... };
In a member function of derived, I want to call
connect(this, &derived::foo);
but it seems that &derived::foo is actually a member function pointer of base; gcc spits out
error: no matching function for call to ‘connect(derived* const&, void (base::* const&)())’
I can get around this by explicitly casting this to base *; but why can’t the compiler match the call with desttype = base (since derived * can be implicitly cast to base *)?
Also, why is &derived::foo not a member function pointer of derived?
Firstly, when you do
&class::memberthe type of the result is always based on the class that member actually declared in. That’s just how unary&works in C++.Secondly, the code does not compile because the template argument deduction fails. From the first argument it derives that
desttype = derived, while from the second one it derives thatdesttype = base. This is what makes the compilation to fail. The template argument deduction rules in C++ don’t consider the fact thatthiscan be converted tobase *type. Moreover, one can argue that instead of convertingthistobase *type, the proper way would be to convert&derived::foofrom pointer-to-base-member to pointer-to-derived-member type. Both approaches are equally viable (see below).Thirdly, member pointers in C++ obey the rules of contra-variance, which means that a pointer to a base class member can be implicitly converted to a pointer to a derived class member. In your case, all you need to do is to help the compiler get through template argument deduction by specifying the argument explicitly, and the code should compile
The above should compile because of contra-variance of
&derived::foopointer, even though it is a pointer tobasemember. Alternatively you can doThis should also compile because of covariance of
thispointer.You can also use explicit casts on the actual arguments (as you mention in the question) to get through the deduction ambiguity, but in my opinion in this case the explicitly specified template argument looks better.