模板参数接受指向类成员函数的指针

时间:2017-01-24 14:50:53

标签: c++

#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;
}

尝试运行此代码(GCC 7.0)会出现以下错误:

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);
                           ^

我真的不明白为什么基类的方法是个问题?它也是派生类的方法。我已经完成了一个简单的测试,我将Derived::base分配到Derived::*ptr类型并且有效。

2 个答案:

答案 0 :(得分:3)

  

我真的不明白为什么基类的方法是个问题?

这只是一个类型的问题。 &Derived::derived的类型为void (Derived::*)(),但&Derived::base的类型为void (Base::*)()。这与void (Derived::*)(Args...)不匹配,因此扣除失败。模板推导不允许进行转换,即使在这种情况下存在有效转换也是如此。

  

我已经完成了简单的测试,我将Derived::base分配到Derived::*ptr类型,并且有效。

此:

MemberFuncPtr<> d = &Derived::base;
wrapper(d);

有效,因为现在d属于正确的类型(现在 匹配void (Derived::*)(Args...)),第一行很好,因为它有效转换指向基类成员的指针,指向派生类成员的指针。

答案 1 :(得分:1)

  

我真的不明白为什么基类中的方法是个问题?

@Barry已经在his answer中解释了原因 作为旁注,请注意您可以进一步概括并使其正常工作:

// ...

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)
{
    // ...
}