我注意到将{const}引用作为参数传递给std::async
是不可能的。
#include <functional>
#include <future>
void foo(int& value) {}
int main() {
int value = 23;
std::async(foo, value);
}
我的编译器(GCC 4.8.1)为此示例提供了以下错误:
error: no type named ‘type’ in ‘class std::result_of<void (*(int))(int&)>’
但是,如果我将std::async
中传递给std::reference_wrapper
的值包装好,那么一切正常。我假设这是因为std::async
按值获取它的参数,但我仍然不明白错误的原因。
答案 0 :(得分:27)
这是一个刻意的设计选择/权衡。
首先,不一定能够找出传递给async
的functionoid是否通过引用获取其参数。 (例如,如果它不是一个简单的函数而是一个函数对象,它可能会有一个重载的函数调用操作符。)所以async
不能说,“嘿,让我只检查一下目标函数想要什么,我就是我会做正确的事。“
所以设计问题是,如果可能的话,它是否会引用所有参数(即,如果它们是左值),还是总是复制?制作副本是安全的选择:副本不能成为悬空,副本不能展示竞争条件(除非它真的很奇怪)。这就是所做出的选择:默认情况下会复制所有参数。
然后,编写该机制,以便它实际上无法将参数传递给非const左值引用参数。这是安全性的另一个选择:否则,您希望修改原始左值的功能会修改副本,从而导致很难追踪的错误。
但是,如果你真的,真的想要非const左值参考参数怎么办?如果您承诺留意悬挂参考和竞争条件,该怎么办?这就是std :: ref的用途。它是对危险引用语义的明确选择。这是你的方式,“我知道我在这里做什么。”
答案 1 :(得分:18)
std::async
(和其他完美转发的函数)查看您传递的参数类型,以确定要执行的操作。他们没有看到最终如何使用这个论点。因此,要通过引用传递对象,您需要告诉std::async
您正在使用引用。但是,简单地传递引用将不会这样做。您必须使用std::ref(value)
通过引用传递value
。
答案 2 :(得分:14)
问题本身与std::async()
只有轻微关系:在定义操作结果时,std::async()
使用std::result_of<...>::type
,其所有参数均为std::decay<...>::type
。这是合理的,因为std::async()
采用任意类型并转发它们以将它们存储在某个位置。要存储它们,函数对象和参数都需要值。因此,使用std::result_of<...>
与此类似:
typedef std::result_of<void (*(int))(int&)>::type result_type;
...并且由于int
无法绑定到int&
(int
不是左值类型,因此需要绑定到int&
) ,这失败了。在这种情况下失败意味着std::result_of<...>
没有定义嵌套的type
。
后续问题可能是:用于实例化std::result_of<...>
的此类型是什么?这个想法是滥用由ResultType(ArgumentTypes...)
组成的函数调用语法:而不是结果类型,传递函数类型,std::result_of<...>
确定调用该函数类型时调用的函数的类型调用给定的参数列表。对于函数指针类型,它实际上并不那么有趣,但函数类型也可以是需要考虑重载的函数对象。基本上,std::result_of<...>
就像这样使用:
typedef void (*function_type)(int&);
typedef std::result_of<function_type(int)>::type result_type; // fails
typedef std::result_of<function_type(std::reference_wrapper<int>)>::type result_type; //OK