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::bla
is int (Base::*)()
, not int (Derived::*)()
, and Base
in that type doesn't match Derived
in your template.
If you want the expression to have type int (Derived::*)()
you must cast it:
func(static_cast<int (Derived::*)()>(&Derived::bla));
But probably it would be better to replace Derived
in the template by a template parameter and then to constrain it to be identical to or a base class of Derived
.
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.