First, when you do &class::member , the type of result is always based on the class on which the member is actually declared. This is how unary & works in C ++.
Secondly, the code does not compile because the output of the template argument is not executed. From the first argument it turns out that desttype = derived , and from the second it is desttype = base . This makes compilation unsuccessful. The rules for outputting template arguments in C ++ do not take into account the fact that this can be converted to base * type. Moreover, it can be argued that instead of converting this to base * correct way would be to convert &derived::foo from a pointer to a base element to a pointer-receiver type. Both approaches are equally viable (see below).
Thirdly, C ++ member pointers obey contra-variance rules, which means that a pointer to an element of a base class can be implicitly converted to a pointer to a member of a derived class. In your case, all you have to do is help the compiler go through the output of the template argument by explicitly specifying the argument, and the code should compile
connect<derived>(this, &derived::foo);
The above should compile due to the inconsistency of the &derived::foo pointer, although this is a pointer to a base member. Alternatively you can do
connect<base>(this, &derived::foo);
This should also compile due to covariance of the this pointer.
You can also use explicit casts of the actual arguments (as you mentioned in the question) to get the ambiguity of the output, but, in my opinion, in this case the explicitly specified template argument looks better.
source share