The following code (condensed from a larger program) does not compile with clang or gcc.
struct S1 {
void m1() {}
};
template<typename B> struct S2 : B {
void m2() {}
void m3();
};
template<typename S, void (S::*m)()> void f1(S* o) {
(o->*m)();
}
template<typename B> void S2<B>::m3() {
f1<S2, &S2::m1>(this);
}
int main() {
void (S2<S1>::*m)() = &S2<S1>::m1;
S2<S1> o;
o.m3();
}
Here is clang’s error message:
bad.cc:15:3: error: no matching function for call to 'f1'
f1<S2, &S2::m1>(this);
^~~~~~~~~~~~~~~
bad.cc:21:5: note: in instantiation of member function 'S2<S1>::m3' requested
here
o.m3();
^
bad.cc:10:43: note: candidate template ignored: invalid explicitly-specified
argument for template parameter 'm'
template<typename S, void (S::*m)()> void f1(S* o) {
^
1 error generated.
This code compiles when I replace m1 by m2. Clearly the compiler knows about m1 (different message when I replace m1 by m4), so why should a pointer to it be invalid in this context?
The thing is, the type of m1 is
void(S1::*)(void), notvoid(S2::*)(void). So fix it by leveraging the known base class name:Of course this doesn’t (yet) scale to methods defined in indirect base classes, but with a bit of TMP it can be done (will see if I can post that while the intermission of Going Native 2012 lasts :))
The more ‘flexible’ approach would be:
You could/should use typetraits to ensure that
S2<B>&is convertible to aB&if the class layout doesn’t already explicitly guarantee that, as in your current example.