#include <utility>
class Base {
public:
virtual ~Base() {}
virtual void base() {}
};
class Derived : public Base {
public:
virtual void derived() {}
};
template<typename... Params>
using MemberFuncPtr = void(Derived::*)(Params...);
template<typename... Params, typename... Args>
void wrapper(MemberFuncPtr<Params...> ptr, Args&&... args)
{
Derived* d = new Derived();
(d->*ptr)(std::forward<Args>(args)...);
delete d;
}
int main()
{
wrapper(&Derived::derived);
wrapper(&Derived::base);
return 0;
}
Trying to run this code (GCC 7.0) gives me the following error:
prog.cc: In function 'int main()':
prog.cc:33:27: error: no matching function for call to 'wrapper(void (Base::*)())'
wrapper(&Derived::base);
^
prog.cc:18:6: note: candidate: template<class ... Params, class ... Args> void wrapper(MemberFuncPtr<Params ...>, Args&& ...)
void wrapper(MemberFuncPtr<Params...> ptr, Args&&... args)
^~~~~~~
prog.cc:18:6: note: template argument deduction/substitution failed:
prog.cc:33:27: note: mismatched types 'Derived' and 'Base'
wrapper(&Derived::base);
^
I don't really understand why method from the base class is an issue? It's also a method for derived class. I've done simple test where I assigned Derived::base
to Derived::*ptr
type and that worked.
I don't really understand why method from the base class is an issue?
It's just a matter of what the types are. The type of &Derived::derived
is void (Derived::*)()
, but the type of &Derived::base
is void (Base::*)()
. That doesn't match void (Derived::*)(Args...)
, so deduction fails. Template deduction doesn't allow for conversions, even if a valid one exists in this case.
I've done simple test where I assigned
Derived::base
toDerived::*ptr
type and that worked.
This:
MemberFuncPtr<> d = &Derived::base;
wrapper(d);
works because now d
is of the right type (it now does match void (Derived::*)(Args...)
), and the first line is fine because it's valid to convert a pointer to member of a base class to a pointer to member of a derived class.
I don't really understand why method from the base class is an issue?
@Barry has already explained the why in his answer .
As a side note, note that you can further generalize it and get it working:
// ...
template<typename T, typename... Params>
using MemberFuncPtr = void(T::*)(Params...);
template<typename T, typename... Params, typename... Args>
void wrapper(MemberFuncPtr<T, Params...> ptr, Args&&... args)
{
// ...
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.