me hicieron unas pruebas utilizando este ejemplo más pequeño que presenta el mismo comportamiento que tenga:
#include <functional>
#include <iostream>
#include <string>
using std::string;
void print(string s1, string s2)
{
std::cout << s1 << s2 << '\n';
}
int main()
{
using namespace std::placeholders;
typedef std::function< void(string) > fn_t;
fn_t func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foo
Tenga en cuenta que he definido un objeto de cadena llamado "foo" en lugar de utilizar literales de cadena. El comportamiento es el mismo, por lo que el problema no está relacionado con esto.
Creo que el problema viene de su typedef. El retorno de bind
(que no se especifica) se convierte en una función tomando string
por valor, mientras que el envoltorio devuelto por bind probablemente toma sus argumentos por rvalue-reference y los reenvía perfectamente. En lugar de usar su propio typedef, debe usar la palabra clave auto
, de modo que el compilador deduzca automáticamente el tipo de func
. Si modificamos el principal de la siguiente manera, obtenemos el comportamiento esperado:
int main()
{
using namespace std::placeholders;
auto func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foofoo
Otra solución es reemplazar el typedef para que func
toma su parámetro por referencia a const:
typedef std::function< void(string const &) > fn_t;
Pongo 'Realmente entiendo por qué el otro typedef no funciona ... Es de suponer que la cadena se mueve, como @ipc notó, pero no sé en qué punto de la ejecución sucede esto. Ni siquiera estoy seguro de que esto sea un comportamiento estándar, ya que tanto function
como el contenedor devuelto por bind
deben usar el reenvío perfecto. Quizás GCC incluye algunas optimizaciones que mueven los argumentos del contenedor cuando se pasan por valor?
Edición
Hice algunas pruebas, resulta que la aplicación de std::function
de GCC realiza un movimiento en sus argumentos, mientras que el retorno envoltorio por std::bind
no lo hace. Todavía no sé si esto es estándar, voy a escribir una pregunta sobre eso.
Pregunta muy interesante, ¡no esperaba tal comportamiento! –
Solo para agregar algunas correcciones: Esto no es realmente currying. Los argumentos vinculantes y el currying son dos operaciones muy similares pero distintas, que no deben confundirse. Currying significa tomar una función que toma una función de N argumentos y convertirla en una función de un argumento que devuelve una función de un argumento que devuelve una función de un argumento ... (repetido n veces). Puede usar 'std :: bind' para implementar una función' curry' que hace esto por usted (hasta cierto punto). De forma similar, puede usar currying para implementar el enlace de argumentos en el modo de 'std :: bind'. – LiKao
@LiKao: De hecho, 'bind' permite [aplicación parcial] (http://en.wikipedia.org/wiki/Partial_application), no currying. –