2017-01-24 3 views
3
#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, и это сработало.

ответ

3

I don't really understand why method from the base class is an issue?

Это всего лишь вопрос того, что такое типы. Тип &Derived::derived - void (Derived::*)(), но тип &Derived::base - void (Base::*)(). Это не соответствует void (Derived::*)(Args...), поэтому вычет не выполняется. Вычисление шаблона не допускает конверсий, даже если в этом случае существует действующий.

I've done simple test where I assigned Derived::base to Derived::*ptr type and that worked.

Это:

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

работает, потому что теперь d имеет правильный тип (теперь делает матч void (Derived::*)(Args...)) и первой линии прекрасно, потому что она действует, чтобы преобразовать указатель на член базового класса к указателю на член производного класса.

+0

То, что я думаю, что я должен помнить о том, что шаблон вычет не допускает преобразования. Благодаря! –

1

I don't really understand why method from the base class is an issue?

@ Барри уже объяснил, почему в 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) 
{ 
    // ... 
} 
+0

Я был обеспокоен тем, что меня заставят называть сайт вызова 'void (Derived :: *)()'. Хорошо знать, что дополнительный параметр может справиться с этой проблемой «другого типа». –

Смежные вопросы