[英]generic member function pointer as a template parameter
考虑这个代码:
#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);
}
当然,这不会在第 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);
}
令人惊讶的是,g++ 并没有抱怨Args
不是模板列表中的最后一个参数,但无论如何它无法将proxycall
绑定到正确的模板函数,只是指出它是一个可能的候选者。
有什么解决办法吗? 我最后的手段是将成员函数指针作为参数传递,但如果我可以将它作为模板参数传递,它会更适合我的其余代码。
编辑:正如一些人指出的那样,这个例子似乎毫无意义,因为 proxycall 不会传递任何参数。 这在我正在处理的实际代码中并非如此:参数是通过 Lua 堆栈中的一些模板技巧获取的。 但是那部分代码与问题无关,而且相当冗长,所以我不会在这里粘贴。
你可以尝试这样的事情:
template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
用法: 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)...);
}
};
用法:
hello obj;
proxy<void(hello::*)(), &hello::f>::call(obj);
// or
typedef proxy<void(hello::*)(), &hello::f> hello_proxy;
hello_proxy::call(obj);
在现代 C++ 中,可以使用template<auto>
和通用 lambda 包装器:
#include <utility>
#include <functional>
template<auto mf, typename T>
auto make_proxy(T && obj)
{
return [&obj] (auto &&... args) { return (std::forward<T>(obj).*mf)(std::forward<decltype(args)>(args)...); };
}
struct R {};
struct A {};
struct B {};
struct Foo
{
R f(A &&, const B &) { return {}; }
//R f(A &&, const B &) const { return {}; }
};
int main()
{
Foo foo;
make_proxy<&Foo::f>(foo)(A{}, B{});
//make_proxy<static_cast<R (Foo::*)(A &&, const B &) const>(&Foo::f)>(std::as_const(foo))(A{}, B{});
//make_proxy<static_cast<R (Foo::*)(A &&, const B &)>(&Foo::f)>(foo)(A{}, B{});
}
如果有重载,应该像在注释代码中一样显式指定成员函数类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.