I'm trying to bind an rvalue reference to a lambda using std::bind
, but I have issues when I throw that into a std::async
call: (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()
This issues a compiler error I'm not really sure how to interpret:
error: no type named 'type' in 'class std::result_of(std::basic_string)>&()>'
What's going on here? Interestingly, a slight modification does compile and work as expected. If I change std::string{"hello world"}
to a c-string literal, everything works fine: (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
Why does this work but not the first example?
std::bind
is going to make a copy of thestd::string
argument and pass that to the lambda. But that fails to compile because the lambda requires an rvalue argument, while whatbind
passes it will be an lvalue. You could get this to work if you getbind
tomove
the argument, but this requires extremely ugly casting for disambiguation (becausestd::move
is an overloaded function).Live demo
You could, of course, write your own version of
move
that is not overloaded, and avoid that cast.The second case works because when
bind
passes thechar const *
to the lambda, an rvaluestd::string
temporary is created implicitly.To explain the error message you're seeing, somewhere within the innards of
std::async
,std::result_of
is being invoked to determine the return type of the function call expression. However, because that call expression is invalid due to the reasons explained above,result_of
is being SFINAE'd out (this is a C++14 change). Hence the errorerror: no type named 'type' in 'class std::result_of<...>'
.