Zrobiłem kilka testów przy użyciu tego mniejszego przykład, który wykazuje takie samo zachowanie Masz:
#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
pamiętać, że określony obiekt String o nazwie „foo” zamiast używać literały ciągów. Zachowanie jest takie samo, więc problem nie jest z tym związany.
Myślę, że problem pochodzi z twojego typedef. Zwrot z bind
(który jest nieokreślony) jest rzutowany na funkcję przyjmującą wartość string
według wartości, podczas gdy opakowanie zwrócone przez bind prawdopodobnie bierze swoje argumenty za pomocą rvalue-reference i idealnie przekazuje je dalej. Zamiast używać własnego słowa kluczowego, powinieneś użyć słowa kluczowego auto
, aby typ func
został automatycznie wyprowadzony przez kompilator. Jeśli będziemy modyfikować główny następująco otrzymujemy oczekiwane zachowanie:
int main()
{
using namespace std::placeholders;
auto func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foofoo
Innym rozwiązaniem jest wymienić typedef tak że func
bierze swoją parametr przez odniesienie do const:
typedef std::function< void(string const &) > fn_t;
I don Naprawdę rozumiem, dlaczego drugi typedef nie działa ... Przypuszczalnie ciąg jest przenoszony, jak zauważyła @ipc, ale nie wiem, w którym momencie wykonania tak się dzieje. Nie jestem nawet pewien, czy jest to standardowe zachowanie, ponieważ zarówno function
, jak i opakowanie zwrócone przez bind
powinny używać idealnego przekazywania. Być może GCC zawiera pewne optymalizacje, które przesuwają argumenty opakowania, gdy są przekazywane przez wartość?
Edit
Zrobiłem kilka testów, okazuje się wdrożenie GCC z std::function
wykonuje ruch na swoich argumentów, natomiast powrót wrapper przez std::bind
nie. Nadal nie wiem, czy to jest standardowe, zamierzam napisać pytanie na ten temat.
Bardzo interesujące pytanie, nie spodziewałbym się takiego zachowania! –
Po prostu dodać korektę: To nie jest naprawdę przygnębiające. Wiążące argumenty i curry to dwie bardzo podobne, ale wciąż odrębne operacje, których nie należy mylić. Currying oznacza przyjęcie funkcji, która przyjmuje funkcję N argumentów i przekształca ją w funkcję jednego argumentu, który zwraca funkcję jednego argumentu, który zwraca funkcję jednego argumentu ... (powtórzone n razy). Możesz użyć 'std :: bind' do zaimplementowania funkcji' curry', która robi to za Ciebie (w pewnym zakresie). Podobnie możesz użyć currying do implementacji wiązania argumentów w sposób 'std :: bind'. – LiKao
@LiKao: Rzeczywiście, "bind" pozwala [częściowe zastosowanie] (http://en.wikipedia.org/wiki/Partial_application), a nie curry. –