ho fatto alcuni test utilizzando questo esempio più piccolo che presenta lo stesso comportamento si ha:
#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
Si noti che ho definito un oggetto stringa denominata "pippo" invece di utilizzare stringhe letterali. Il comportamento è lo stesso, quindi il problema non è correlato a questo.
Penso che il problema derivi dal typedef. Il ritorno di bind
(che non è specificato) è assegnato a una funzione prendendo un string
dal valore, mentre il wrapper restituito dal binding probabilmente prende i suoi argomenti in base al riferimento-valore e li inoltra perfettamente. Invece di utilizzare il proprio typedef, è necessario utilizzare la parola chiave auto
, in modo che il tipo di func
venga dedotto automaticamente dal compilatore. Se modifichiamo il principale come segue, si ottiene il comportamento previsto:
int main()
{
using namespace std::placeholders;
auto func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foofoo
Un'altra soluzione è quella di sostituire il vostro typedef in modo che func
prende il parametro per riferimento-a-const:
typedef std::function< void(string const &) > fn_t;
I don capisco davvero perché l'altro typedef non funzioni ... Presumibilmente la stringa viene spostata, come notato da @ipc, ma non so a che punto dell'esecuzione ciò avvenga. Non sono nemmeno sicuro che si tratti di un comportamento standard, dal momento che siache il wrapper restituito da bind
devono utilizzare l'inoltro perfetto. Forse GCC include alcune ottimizzazioni che spostano gli argomenti del wrapper quando vengono passati per valore?
Modifica
ho fatto alcuni test, si scopre l'implementazione di GCC di std::function
esegue una mossa suoi argomenti, mentre il ritorno da involucro std::bind
non lo fa. Non so ancora se questo è standard, ho intenzione di scrivere una domanda al riguardo.
Domanda molto interessante, non mi sarei mai aspettato un simile comportamento! –
Solo per aggiungere qualche correzione: questo non è davvero un curriculum. Argomenti vincolanti e curring sono due operazioni molto simili ma comunque distinte, che non devono essere confuse. Currying significa assumere una funzione che prende una funzione di N argomenti e trasformarla in una funzione di un argomento che restituisce una funzione di un argomento che restituisce una funzione di un argomento ... (ripetuto n volte). Puoi usare 'std :: bind' per implementare una funzione' curry' che fa questo per te (in qualche modo). Allo stesso modo è possibile utilizzare il currying per implementare l'associazione degli argomenti nel modo di 'std :: bind'. – LiKao
@LiKao: Infatti, 'bind' consente [applicazione parziale] (http://en.wikipedia.org/wiki/Partial_application), non in fase di elaborazione. –