【问题标题】:std::async using an rvalue reference bound to a lambdastd::async 使用绑定到 lambda 的右值引用
【发布时间】:2015-07-17 00:57:09
【问题描述】:

我正在尝试使用 std::bind 将右值引用绑定到 lambda,但是当我将其放入 std::async 调用时遇到问题:(source)

auto lambda = [] (std::string&& message) {
    std::cout << message << std::endl;
};
auto bound = std::bind(lambda, std::string{"hello world"});
auto future = std::async(bound); // Compiler error here
future.get()

这会引发一个编译器错误,我不确定如何解释:

错误:'class std::result_of(std::basic_string)>&()>'中没有​​名为'type'的类型

这里发生了什么?有趣的是,稍作修改就可以按预期编译和工作。如果我将 std::string{"hello world"} 更改为 c 字符串文字,一切正常:(source)

auto lambda = [] (std::string&& message) {
    std::cout << message << std::endl;
};
auto bound = std::bind(lambda, "hello world");
auto future = std::async(bound);
future.get(); // Prints "hello world" as expected

为什么这行得通,但不是第一个例子?

【问题讨论】:

  • 如果 lambda 是用 auto lambda = [] (std::string&amp; message) 定义的(参考,而不是右值),它也可以工作
  • 我也注意到了,虽然它应该是const string&amp; message,否则它会拒绝接受 c-string 文字。
  • async为你做绑定:std::async(lambda, std::string{"hello world"})

标签: c++ c++11 lambda stdbind


【解决方案1】:

std::bind 将复制std::string 参数并将其传递给 lambda。但这无法编译,因为 lambda 需要一个右值参数,而 bind 传递的将是一个左值。如果您将 bind 设置为 move 参数,则可以使其正常工作,但这需要非常难看的类型来消除歧义(因为 std::move 是一个重载函数)。

auto bound = std::bind(lambda, std::bind(static_cast<std::string&&(*)(std::string&)>(std::move),
                                         std::string{"hello world"}));

Live demo

当然,您可以编写自己的 move 版本,但不会重载,并避免这种转换。

第二种情况有效,因为当bindchar const * 传递给lambda 时,会隐式创建一个右值std::string


为了解释您看到的错误消息,在 std::async 的内部某处,正在调用 std::result_of 以确定函数调用表达式的返回类型。但是,由于上述原因,该调用表达式无效,result_of 被 SFINAE 淘汰(这是 C++14 更改)。因此出现错误error: no type named 'type' in 'class std::result_of&lt;...&gt;'

【讨论】:

  • 呃。是的,这太丑了。
  • 非常聪明。有道理,因为 lambda("hello world") 会编译,但 auto s = std::string{"hello world"}; lambda(s) 不会。
  • 在这种情况下的另一个选择是创建一个新的 lambda。 auto bound = [lambda,msg=std::string{"hello world"}]() mutable { lambda(std::move(msg)); };
  • @Brian,你是对的,广义的 lambda 捕获将消除对 std::bind 的需要。不过,我目前仅限于 C++11,因此这在我的情况下不起作用,但如果 C++14 确实成为一种选择,那么很高兴知道。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-17
  • 1970-01-01
  • 2022-06-12
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多