'variable' 不是类型 'pointer to member function' 的有效模板参数

'variable' is not a valid template argument for type 'pointer to member function'

本文关键字:有效 参数 function pointer variable 类型 to member      更新时间:2023-10-16

我对C++和模板都很陌生,我正在尝试调整一个可以用来从成员函数中进行委托的助手类。

我更改了这个代码(编译):

Delegate<void, int, int>* cheaty(void (Renderer::*method)(int, int), Renderer* obj)
    {
         auto maker = DelegateMaker<Renderer, void, int, int>();
         return maker.BindPointer<&Renderer::MoveCamera>(obj);
    }

对此:

 Delegate<void, int, int>* cheaty(void (Renderer::*method)(int, int), Renderer* obj)
    {
         auto maker = DelegateMaker<Renderer, void, int, int>();
         return maker.BindPointer<method>(obj);
    }

它不编译,并给出以下错误:error: 'method' is not a valid template argument for type 'void (Engine::Renderer::*)(int, int)'。是不是因为C++模板的限制,我试图实现的目标根本不可能实现?还是我只是错过了一些显而易见的东西?

编辑:理想情况下,我想要的是这样一个函数:

    template<typename T, typename return_type, typename... params>
    Delegate<return_type, params...>*   make_delegate_pointer(return_type (T::*name)(params...), T* obj)
    {
        DelegateMaker<T, return_type, params...> maker = DelegateMaker<T, return_type, params...>();
        return maker.BindPointer<name>(obj);
    }

然后像这样调用它auto delegate = Delegates::make_delegate_pointer(&Class::Method, &classInstance); Only,我一直遇到的问题是,像这样调用BindPointer maker.BindPointer<&Class::Method>(classInstance);和像这样调用maker.BindPointer<return_type (Class::*)(arguments...)>(classInstance);之间似乎有一些区别。

然而,return_type (T::*)(params...) memberFuncPointer = &Class::Method编译良好。这意味着从逻辑上讲,maker.BindPointer<return_type (T::*)(params...)>(classInstance)也应该编译(或者是它的一些变体,这就是为什么在最初的问题中我试图使用method作为void (Renderer::*method)(int, int))。但事实并非如此。

模板参数值必须在编译时已知,但您的method值直到运行时才知道,因为cheaty()不知道传递给它的是Renderer的哪种方法。因此编译器出错。您必须更改BindPointer才能不再使用模板。此外,DelegateMaker已经知道方法签名,因此不需要将该信息复制为BindPointer()中的模板参数,让它继承DelegateMaker中的值。

例如(未经测试,可能需要一些调整,但您应该了解大致想法):

template <typename ReturnType, typename... ParamTypes>
class Delegate
{
public:
    virtual ReturnType Invoke(ParamTypes... params) = 0;
};
template <typename ClassType, typename ReturnType, typename... ParamTypes>
class DelegateMaker
{
public:
    typedef ReturnType (ClassType::*MethodType)(ParamTypes... params);
private:
    class DelegateImpl : public Delegate<ReturnType, ParamTypes...> 
    {
    private:
        ClassType* _obj;
        MethodType _method;
    public:
        DelegateImpl(ClassType *obj, MethodType method)
            : _obj(obj), _method(method)
        {
        }
        virtual ReturnType Invoke(ParamTypes... params)
        {
            return (_obj.*_method)(params);
        }
    };
public:
    Delegate<ReturnType, ParamTypes...>* BindPointer(MethodType method, ClassType *obj)
    {
        return new DelegateImpl(obj, method);
    }
};

template <typename ClassType, typename ReturnType, typename... ParamTypes>
Delegate<ReturnType, ParamTypes...>* make_delegate_pointer(
    DelegateMaker<ClassType, ReturnType, ParamTypes...>::MethodType method,
    ClassType* obj)
{
    DelegateMaker<ClassType, ReturnType, ParamTypes...> maker;
    return maker.BindPointer(method, obj);
}

auto delegate = Delegates::make_delegate_pointer(&Class::Method, &classInstance);