在我下面的代码中,我有一个函数接受“通用引用”(F&&
)。该函数还有一个内部类,它接受 F&&
的对象。在它的构造函数中。是F&&
在这一点上仍然是一个普遍的引用? IE。是F
仍然认为是推导类型?
换句话说,我应该使用 std::forward<F>
吗?或 std::move
在构造函数初始化列表中?
#include "tbb/task.h"
#include <iostream>
#include <future>
template<class F>
auto Async(F&& f) -> std::future<decltype(f())>
{
typedef decltype(f()) result_type;
struct Task : tbb::task
{
Task(F&& f) : f_(std::forward<F>(f)) {} // is forward correct here?
virtual tbb::task* execute()
{
f_();
return nullptr;
}
std::packaged_task<result_type()> f_;
};
auto task = new (tbb::task::allocate_root()) Task(std::forward<F>(f));
tbb::task::enqueue(*task);
return task->f_.get_future();
}
int main()
{
Async([]{ std::cout << "Hi" << std::endl; }).get();
}
最佳答案
Is
F&&
still a universal reference at that point? I.e. isF
still considered to be a deduced type?
这种混淆是我不喜欢通用引用这个词的原因...... there's no such thing .
我更喜欢根据左值引用和右值引用以及引用折叠和模板参数推导规则来理解代码。
当使用 L
类型的左值调用函数时,参数 F
将被推导为 L&
,并通过引用折叠规则F&&
就是 L&
。在 Task
构造函数中没有任何变化,F&&
仍然是 L&
因此构造函数采用绑定(bind)到传递给 的左值的左值引用Async
,所以你不想移动它,forward
是合适的,因为它保留了值类别,将左值作为左值转发。 (从左值移动会让 Async
的调用者感到惊讶,他们不会期望左值被静静地移动。)
当使用 R
类型的右值调用函数时,参数 F
将被推导为 R
,因此 F&&
是 R&&
。在 Task
构造函数中没有任何变化,F&&
仍然是 R&&
因此构造函数采用绑定(bind)到传递给 的右值的右值引用异步
,因此您可以移动它,但forward
也是合适的,因为它保留值类别,将右值作为右值转发。
在上周的 CppCon 上,Herb Sutter 宣布“通用引用”的首选术语现在是转发引用,因为这更好地描述了它们的用途。
关于c++ - 通用引用和本地类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25909134/