通用成员函数指针作为模板参数

Lor*_*one 24 c++ function-pointers variadic-templates c++11

考虑以下代码:

#include <iostream>
using namespace std;

class hello{
public:
    void f(){
        cout<<"f"<<endl;
    }
    virtual void ff(){
        cout<<"ff"<<endl;
    }
};

#define call_mem_fn(object, ptr)  ((object).*(ptr))

template<R (C::*ptr_to_mem)(Args...)> void proxycall(C& obj){
    cout<<"hello"<<endl;
    call_mem_fn(obj, ptr_to_mem)();
}

int main(){
    hello obj;
    proxycall<&hello::f>(obj);
}
Run Code Online (Sandbox Code Playgroud)

当然,这不会在第16行编译,因为编译器不知道是什么R,C并且Args,是.但还有另一个问题:如果有人试图在之前定义这些模板参数ptr_to_mem,他会遇到这种糟糕的情况:

template<typename R, typename C, typename... Args, R (C::*ptr_to_mem)(Args...)> 
                             //  ^variadic template, but not as last parameter!
void proxycall(C& obj){
    cout<<"hello"<<endl;
    call_mem_fn(obj, ptr_to_mem)();
}

int main(){
    hello obj;
    proxycall<void, hello, &hello::f>(obj);
}
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,g ++没有抱怨Args不是模板列表中的最后一个参数,但无论如何它不能绑定proxycall到正确的模板函数,只是注意到它是一个可能的候选者.

有解决方案吗 我最后的办法是将成员函数指针作为参数传递,但如果我可以将它作为模板参数传递,它将更适合我的其余代码.

编辑:正如一些人所指出的那样,这个例子似乎毫无意义,因为proxycall不会传递任何参数.在我正在处理的实际代码中并非如此:使用Lua堆栈中的一些模板技巧获取参数.但是这部分代码与问题无关,而且相当冗长,所以我不会在这里粘贴它.

Ker*_* SB 39

你可以尝试这样的事情:

template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
    return (obj.*mf)(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

用法: proxycall(obj, &hello::f);

或者,要将PTMF变为模板参数,请尝试使用专门化:

template <typename T, T> struct proxy;

template <typename T, typename R, typename ...Args, R (T::*mf)(Args...)>
struct proxy<R (T::*)(Args...), mf>
{
    static R call(T & obj, Args &&... args)
    {
        return (obj.*mf)(std::forward<Args>(args)...);
    }
};
Run Code Online (Sandbox Code Playgroud)

用法:

hello obj;

proxy<void(hello::*)(), &hello::f>::call(obj);

// or

typedef proxy<void(hello::*)(), &hello::f> hello_proxy;
hello_proxy::call(obj);
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记处理`const`成员函数.(但如果你决定不打扰`volatile`或`const volatile`,我不会抱怨.) (3认同)
  • @ user1810087:const限定的成员函数指针类型是`R(T :: *)(Args ...)const`。 (3认同)
  • @nilo 感谢您指出“auto”,这似乎[恰好解决了这个问题](/sf/answers/2663097601/)。否则,如果没有此功能,可以使用 decltype(hello::f) 来消除第一个模板参数的签名复杂性。 (2认同)