std :: bind una función enlazada

Tengo problemas para detectar por qué diablos no está comstackndo. Tengo una función lambda que devuelve una std::function basada en algún argumento.

He reducido mi problema a este fragmento (que no usa lambdas, pero reproduce mi error perfectamente):

 #include  #include  struct foo { template void bar(T data) { std::cout << data << "\n"; } }; void some_fun(const std::function &f) { f(12); } int main() { foo x; auto f = std::bind(&foo::bar, x, std::placeholders::_1); auto w = std::bind(some_fun, f); w(); } 

La llamada a w() produce uno de esos encantadores resultados de error de gcc en los que no puedo entender qué está pasando mal. Este es el error echo por gcc 4.6.1:

 g++ -std=c++0x test.cpp -o test test.cpp: In function 'int main()': test.cpp:20:7: error: no match for call to '(std::_Bind<void (*(std::_Bind<std::_Mem_fn(foo, std::_Placeholder)>))(const std::function&)>) ()' /usr/include/c++/4.6/functional:1130:11: note: candidates are: /usr/include/c++/4.6/functional:1201:2: note: template _Result std::_Bind::operator()(_Args&& ...) [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function&), _Bound_args = {std::_Bind<std::_Mem_fn(foo, std::_Placeholder)>}] /usr/include/c++/4.6/functional:1215:2: note: template _Result std::_Bind::operator()(_Args&& ...) const [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function&), _Bound_args = {std::_Bind<std::_Mem_fn(foo, std::_Placeholder)>}] /usr/include/c++/4.6/functional:1229:2: note: template _Result std::_Bind::operator()(_Args&& ...) volatile [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function&), _Bound_args = {std::_Bind<std::_Mem_fn(foo, std::_Placeholder)>}] /usr/include/c++/4.6/functional:1243:2: note: template _Result std::_Bind::operator()(_Args&& ...) const volatile [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function&), _Bound_args = {std::_Bind<std::_Mem_fn(foo, std::_Placeholder)>}] 

Aquí, f debe ser un objeto invocable que toma un int como argumento y lo llama x.bar(int) . Por otro lado, w es simplemente un objeto invocable que llama a some_fun(f) , siendo f el objeto invocable mencionado anteriormente, que tiene la firma esperada por el parámetro some_fun .

¿Me estoy perdiendo de algo? Probablemente no sé cómo mezclar std::bind y std::function .

std::bind expressions, como sus boost::bind predecessors, admiten un tipo de operación de composición. Tu expresión para w es más o menos equivalente a

 auto w=std::bind(some_fun, std::bind(&foo::bar, x, std::placeholders::_1) ); 

El anidamiento se une de esta manera se interpreta como

  1. Calcule el valor de x.bar(y) donde y es el primer parámetro que se pasa al funtor resultante.
  2. Pase ese resultado a some_fun .

Pero x.bar(y) devuelve vacío, no cualquier tipo de función. Es por eso que esto no comstack.

Como señala K-ballo, con boost::bind , puede solucionar este problema con boost::protect . Como señalan Kerrek SB y ildjarn, una forma de evitar este problema es: no use auto para f . No quiere que f tenga el tipo de expresión de enlace. Si f tiene algún otro tipo, std::bind no intentará aplicar las reglas de composición de funciones. Puede, por ejemplo, dar f el tipo std::function :

 std::function f = std::bind(&foo::bar, x, std::placeholders::_1); auto w = std::bind(some_fun, f); 

Dado que f no tiene literalmente el tipo de una expresión de std::is_bind_expression<>::value , std::is_bind_expression<>::value será falso en el tipo de f , por lo que la expresión std::bind en la segunda línea simplemente pasará el valor en textualmente, en lugar de intentar aplicar las reglas de composición de funciones.

some_fun quiere argumento de tipo const std::function & .

std :: bind devuelve “un objeto de función de tipo T no especificado” (consulte el enlace provisto, sección “Valor de devolución”), que está tratando de pasar como un argumento_de_fun.

Parece que esto causa un problema, porque este tipo de argumento no se espera.

Mira: http://en.cppreference.com/w/cpp/utility/functional/bind