[英]Variadic template as parameters to std::function
我想构建一个允许我用未定义数量的参数调用成员函数的结构。 现在我写了这样的东西
template<typename Class, typename Return, typename ... Args>
struct Caller
{
private:
std::function<Return(Args ...)> callerFunction;
Caller() = delete;
Caller(const Caller&) = delete;
Caller(Caller&&) = delete;
Caller& operator=(const Caller&) = delete;
public:
~Caller() = default;
Caller(Class& instance, Return(Class::*function)(Args ...))
{
callerFunction = [&instance, function](Args... args)
{
return (instance.*function)(args ...);
};
}
Return operator() (Args ... args)
{
return callerFunction(args ...);
}
};
我担心我std::function<Return<Args&& ...)> callerFunction
一个事实:我无法将std :: function变量声明为std::function<Return<Args&& ...)> callerFunction
当我尝试这样做时,编译器说它不能从int
转换为int&&
(例如,如果参数是int
),所以我猜测该函数将Args&& ...
视为rvalue引用的参数包。 我对么?
有解决方法吗?
编辑:好的,我以错误的方式在Caller构造函数中声明了该函数。
错误的方式 - > Caller(Class& instance, Return(Class::*function)(Args&& ...))
正确的方法 - > Caller(Class& instance, Return(Class::*function)(Args ...))
(我猜)正确的实现是
template<typename Class, typename Return, typename ... Args>
struct Caller
{
private:
std::function<Return(Args&& ...)> callerFunction;
Caller() = delete;
Caller(const Caller&) = delete;
Caller(Caller&&) = delete;
Caller& operator=(const Caller&) = delete;
public:
~Caller() = default;
Caller(Class& instance, Return(Class::*function)(Args ...))
{
callerFunction = [&instance, function] (Args&&... args)
{
return (instance.*function)(std::forward<Args>(args) ...);
};
}
Return operator() (Args&& ... args)
{
return callerFunction(std::forward<Args>(args) ...);
}
};
现在的问题是:为什么我需要在没有double&?的情况下声明函数?
当您像这样定义类模板时:
template <typename T>
struct A {
A(T&& param)
}
然后创建一个实例:
A<int> myInstance(someIntVariable);
它不会编译 。 原因是, T
的类型由您明确指定(作为int
,在A<int>
),并且您的类构造函数参数不再是T&&
,而是int&&
,因此它不再是通用引用(它同时接受左值和右值参考),但是常规右值参考。
接下来,如果传递一些整数,则会出现类型不匹配错误,因为在期望rvalue引用时传递常规变量。
在您的示例中,您明确定义了函数签名,因此同样适用 - 构造函数需要一个函数将rvalue引用到Args ...,但事实并非如此。
我认为在这个问题中解释得更好
int&&
与int
。 如果您的方法采用int
,则不需要int&&
。 它们是不同的类型。
成员函数指针的不同签名之间没有转换。
转发引用并不神奇。 它们依赖于演绎规则(并且不使用上面的Args&&...
在推导的上下文中)和参考折叠规则。
就这样,你的
Return operator() (Args&& ... args)
也是错的。 如果Args...
是int
,那么你将无法使用int a; blah.operator()(a)
调用上面int a; blah.operator()(a)
int a; blah.operator()(a)
作为a
不会绑定到int&&
。
老实说,你的整个类型应该被抛出并替换为std::function<Return(Args...)>
。 Class
是函数所做的无用的缩小,你的包装器也不会增加太多。
用户只需[&a](auto&&...args)->decltype(auto){ return a.foo(decltype(args)(args)...); }
[&a](auto&&...args)->decltype(auto){ return a.foo(decltype(args)(args)...); }
如果他们真的需要复制你的构造函数,或使用std::bind( &A::foo, std::ref(a) )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.