c++ - funciones - std:: async usando una referencia rvalue vinculada a un lambda
funciones lambda c++ (1)
Estoy intentando vincular una referencia rvalue a un lambda usando std::bind
, pero tengo problemas cuando lo incluyo en una llamada std::async
: ( fuente )
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()
Esto genera un error del compilador que no estoy seguro de cómo interpretar:
error: ningún tipo llamado ''tipo'' en ''clase std :: result_of (std :: basic_string)> & ()>''
¿Que está pasando aqui? Curiosamente, una ligera modificación se compila y funciona como se esperaba. Si cambio std::string{"hello world"}
a un literal c-string, todo funciona bien: ( fuente )
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
¿Por qué funciona esto pero no es el primer ejemplo?
std::bind
va a hacer una copia del argumento std::string
y pasarlo a la lambda. Pero eso no se puede compilar porque la lambda requiere un argumento rvalue, mientras que lo que pasa es un lvalue. Puedes hacer que esto funcione si obtienes bind
para move
el argumento, pero esto requiere un casting extremadamente desagradable para la desambiguación (porque std::move
es una función sobrecargada).
auto bound = std::bind(lambda, std::bind(static_cast<std::string&&(*)(std::string&)>(std::move),
std::string{"hello world"}));
Por supuesto, podría escribir su propia versión del move
que no esté sobrecargada, y evitar ese lanzamiento.
El segundo caso funciona porque cuando bind
pasa el char const *
al lambda, se crea rvalue std::string
temporary de forma implícita.
Para explicar el mensaje de error que está viendo, en algún lugar dentro de las entrañas de std::async
, std::result_of
se invoca para determinar el tipo de retorno de la expresión de llamada a la función. Sin embargo, debido a que la expresión de llamada no es válida debido a los motivos explicados anteriormente, result_of
está siendo SFINAE (esto es un cambio de C ++ 14). De ahí el error error: no type named ''type'' in ''class std::result_of<...>''
.