Why don't member function temporaries bind to the right type?
c++, templates
Solution
int main(int argc, char** argv) {
void (Porsche::*ptr)(void) = &Porsche::Drive;
Function(&Porsche::Drive, ptr);
return 0;
}
`ptr` has type `void (Porsche::*)()`, but `&Porsche::Drive` has type `void (Car::*)()` (because the member is found in `Car`, not in `Porsche`). Thus the function called compares these two member pointers with those types, and the standard says
In addition, pointers to members can be compared, or a pointer to member and a null pointer constant. Pointer to member conversions (4.11) and qualification conversions (4.4) are performed to bring them to a common type. If one operand is a null pointer constant, the common type is the type of the other operand. Otherwise, the common type is a pointer to member type similar (4.4) to the type of one of the operands, with a cv-qualification signature (4.4) that is the union of the cv-qualification signatures of the operand types.
`4.11` describes an implicit Standard conversion from `void (Base::*)()` to `void (Derived::*)()`. Thus, the comparison would find the common type `void (Porsche::*)()`. For an object of type `Porsche`, both member pointers would refer to the same function (which is `Car::Drive`) - so the comparison would yield true. The comeau web compiler follows this interpretation and compiles your code.
Problem
Suppose that we have the following base and derived classes: ``` #include <string> #include <iostream> class Car { public: void Drive() { std::cout << "Baby, can I drive your car?" << std::endl; } }; class Porsche : public Car { }; ``` ..and also the following template function: ``` template <typename T, typename V> void Function(void (T::*m1)(void), void (V::*m2)(void)) { std::cout << (m1 == m2) << std::endl; } ``` Why does this compile using GCC: ``` int main(int argc, char** argv) { void (Porsche::*ptr)(void) = &Porsche::Drive; Function(ptr, ptr); return 0; } ``` ...but not this? ``` int main(int argc, char** argv) { void (Porsche::*ptr)(void) = &Porsche::Drive; Function(&Porsche::Drive, ptr); return 0; } ```