C++ 泛型成员函数指针作为模板参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9779105/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:16:52  来源:igfitidea点击:

generic member function pointer as a template parameter

c++c++11function-pointersvariadic-templates

提问by Lorenzo Pistone

Consider this code:

考虑这个代码:

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

Of course this won't compile at line 16, because the compiler doesn't know what R, Cand Args, are. But there's another problem: if one tries to define those template parameters right before ptr_to_mem, he runs into this bad situation:

当然,这不会在第 16 行编译,因为编译器不知道RCArgs是什么。但是还有另一个问题:如果试图在之前定义这些模板参数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);
}

Surprisingly, g++ does not complain about Argsnot being the last parameter in the template list, but anyway it cannot bind proxycallto the right template function, and just notes that it's a possible candidate.

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

Any solution? My last resort is to pass the member function pointer as an argument, but if I could pass it as a template parameter it would fit better with the rest of my code.

有什么解决办法吗?我最后的手段是将成员函数指针作为参数传递,但如果我可以将它作为模板参数传递,它会更适合我的其余代码。

EDIT: as some have pointed out, the example seems pointless because proxycall isn't going to pass any argument. This is not true in the actual code I'm working on: the arguments are fetched with some template tricks from a Lua stack. But that part of the code is irrelevant to the question, and rather lengthy, so I won't paste it here.

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

回答by Kerrek SB

You could try something like this:

你可以尝试这样的事情:

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

Usage: proxycall(obj, &hello::f);

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

Alternatively, to make the PTMF into a template argument, try specialization:

或者,要使 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)...);
    }
};

Usage:

用法:

hello obj;

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

// or

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