The following code does not compile with Clang (but compiles fine with MSVC):
class Base {
public:
int bla() { return 1; }
};
class Derived : public Base {
};
template <typename T>
void func(T (Derived::*method)()) {
}
int main() {
func(&Derived::bla);
}
With the error:
<source>:19:3: error: no matching function for call to 'func'
19 | func(&Derived::bla);
| ^~~~
<source>:13:6: note: candidate template ignored: could not match 'Derived' against 'Base'
13 | void func(T (Derived::*method)())
| ^
See on Compiler Explorer.
Which compiler is correct W.R.T. the standard?
Clang is correct. The type of the expression
&Derived::blaisint (Base::*)(), notint (Derived::*)(), andBasein that type doesn't matchDerivedin your template.If you want the expression to have type
int (Derived::*)()you must cast it:But probably it would be better to replace
Derivedin the template by a template parameter and then to constrain it to be identical to or a base class ofDerived.Consider whether you really need a specific pointer-to-member as function argument at all. Generally it would be sufficient to allow any type and then constrain on
std::invoke(method, std::declval<Dervived*>())being well-formed. Then it would work without cast and a user could pass a lambda or anything else suitable as well.