std :: async使用绑定到lambda的rvalue引用

huu*_*huu 8 c++ lambda stdbind c++11

我正在尝试将一个rvalue引用绑定到一个lambda使用std::bind,但是当我把它扔进一个std::async调用时我遇到了问题:( 来源)

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()
Run Code Online (Sandbox Code Playgroud)

这会发出编译器错误我不确定如何解释:

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

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

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
Run Code Online (Sandbox Code Playgroud)

为什么这有效但不是第一个例子?

Pra*_*ian 11

std::bind将创建std::string参数的副本并将其传递给lambda.但是由于lambda需要一个rvalue参数而没有编译,而bind传递它的是一个左值.你可以得到这个如果你的工作bindmove的说法,但是这需要极其丑陋铸件消除歧义(因为std::move是一个重载函数).

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

现场演示

当然,您可以编写自己的版本,move但不会超载,并避免使用该转换.

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


为了解释您正在查看的内容中的错误消息std::async,std::result_of正在调用以确定函数调用表达式的返回类型.但是,由于上面解释的原因,该调用表达式无效,result_of因此正在SFINAE出局(这是C++ 14的更改).因此错误error: no type named 'type' in 'class std::result_of<...>'.

  • 啊.是的,那很丑陋. (4认同)