[英]How to pass a Callable object in c++17 to be used with std::invoke
Why the following does not compile when passing i
to the constructor.为什么以下在将
i
传递给构造函数时无法编译。 The other similar constructs compile.其他类似的结构编译。
#include <iostream>
#include <functional>
int RetXPrintU(int x, uint u)
{
std::cout << "RetXprintU(): " << u << std::endl;
return x;
}
template <typename Fn, typename... Args>
void Call(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
int main() {
int i = 4;
std::invoke(RetXPrintU, i, 8u);
Call(RetXPrintU, i, 8u);
CallableObj co(RetXPrintU, i, 8u); // WHY I DO NOT COMPILE?
//CallableObj co(RetXPrintU, 0, 8u); // WHY I COMPILE?
return 0;
}
The issue here is you need to move the template from the class to the constructor.这里的问题是您需要将模板从类移动到构造函数。 When you have
当你有
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
Args&&...
is not a variadic forwarding reference because it is deduced for the class itself and when you call CallableObj co(RetXPrintU, i, 8u);
Args&&...
不是可变参数转发引用,因为它是为类本身以及当您调用CallableObj co(RetXPrintU, i, 8u);
推导出来的CallableObj co(RetXPrintU, i, 8u);
the class is instantiated and the constructor gets stamped out as该类被实例化,构造函数被标记为
explicit CallableObj(int(int, unsigned int)&& fun, int&& arg1, unsigned int&& arg2)
What we want is我们想要的是
class CallableObj
{
public:
template <typename Fn, typename... Args>
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
so that now Args
will be deduced when the constructor is called and Args&&
is now a forwarding reference.这样现在在调用构造函数时
Args
导出Args&&
并且Args&&
现在是转发引用。
The reason CallableObj co(RetXPrintU, 0, 8u);
原因
CallableObj co(RetXPrintU, 0, 8u);
worked in your example is because 0
is a prvalue and a prvalue can bind to an rvalue reference.在你的例子中工作是因为
0
是一个纯右值,一个纯右值可以绑定到一个右值引用。
As the error message says, the compiler can't deduce the template parameters for CallableObj
.正如错误消息所说,编译器无法推导出
CallableObj
的模板参数。 You need add a deduction guide for that:您需要为此添加一个扣除指南:
template <typename Fn, typename... Args>
CallableObj(Fn&& fun, Args&&... args) -> CallableObj<Fn, Args>...>;
The whole code reads:整个代码如下:
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn fun, Args... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
template <typename Fn, typename... Args>
CallableObj(Fn&& fun, Args&&... args) -> CallableObj<Fn, Args...>;
As @Jarod42 pointed out there's no need to make the constructor a template itself (as it was in the first version of the answer).正如@Jarod42 指出的那样,没有必要让构造函数本身成为模板(就像在答案的第一个版本中一样)。
And here is a live example (corrected version by @Jarod42).这是一个实时示例(@ Jarod42 的更正版本)。
I was assuming your code is just a minimal example and you need the class to be a template.我假设你的代码只是一个最小的例子,你需要这个类作为模板。 If that is not the case you better go with the other solution.
如果不是这种情况,您最好采用其他解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.