通过引用将参数传递给std :: async失败

时间:2013-08-21 14:14:48

标签: c++ multithreading asynchronous c++11

我注意到将{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按值获取它的参数,但我仍然不明白错误的原因。

3 个答案:

答案 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