2012-11-06 13 views
18

Załóżmy, że mam funkcję, która pobiera dwa argumenty,Dlaczego obiekty zwracane przez bind ignorują dodatkowe argumenty?

void f(int x, int y); 

i chcę się wiązać z nich. Mogę użyć std::bind następująco:

auto partiallyBoundF = std::bind(f, 10, _1); 

partiallyBoundF trwa tylko jeden argument, ale mogę nazwać to z więcej niż jednego. Argumenty poza pierwszy nawet nie muszą być typu, który ma sensu:

partiallyBoundF(20, 0); 
partiallyBoundF(0, 44, -99, "Hello", 4.5, true, []{}); 

Co jest celem pozwalających obiektów zwracanych z bind być przekazywane dodatkowe argumenty? Umożliwia wywoływanie błędów podczas kompilacji, które mogłyby zostać odrzucone w innym miejscu.

+3

Jaki kompilator? Sądzę, że może to być po prostu niezgodny kompilator (ponieważ zezwolenie na te dodatkowe argumenty naprawdę nie ma sensu i wątpię, aby standard to umożliwiał). Na przykład MSVC emuluje szablony variadyczne, definiując po prostu każdy szablon wielościenny, aby pobrać maksymalnie możliwe argumenty z szablonu i przypisać je do pewnego typu NIL. Może coś takiego jest przyczyną twojego zachowania? –

+3

@ ChristianaRau: To część standardu. To także była część TR1. 20.8.2/4 komentuje, że spodziewana implementacja jest dla '' operator() 'z prefiksem variadycznym, aby po prostu brać wszystko, co jest do niego przekazywane, niezależnie od typu lub liczby argumentów. TR1 ma podobne brzmienie. – KnowItAllWannabe

+1

W twoim przypadku f (w1, ..., wN) gdzie 'N = sizeof ... (bound_args)' (liczba argumentów do wywołania wiązania) będzie poprawnym wyrażeniem, patrz 20.8.9.1.2/2 i 20.8.2/1. Edycja: NIE uniemożliwia żadnego innego połączenia. – dyp

Odpowiedz

16

Ignorowanie dodatkowych argumentów jest o wiele łatwiejsze do wdrożenia i może być użyteczne.

W typowej realizacji, np. libstdC++ (g ++), podejście to polega na zebraniu argumentów operator() na krotkę, a następnie pozwól, aby argumenty wiążące std::placeholder wyodrębniły je zgodnie z wymaganiami. Wymuszenie liczby argumentów wymagałoby zliczenia liczby używanych symboli zastępczych, co byłoby dość skomplikowane. Zwróć uwagę, że wywoływalne powiązanie może być funktorem z wieloma wzorcami połączeń wzorcowych operator(), więc obiekt wiązania operator() nie może zostać wygenerowany z pojedynczą "poprawną" sygnaturą.

pamiętać, że można napisać również:

std::bind(&foo, std::placeholders::_1, std::placeholders::_3); 

tj jawnie ignorując drugi argument do obiektu bind. Jeśli bind wymusił liczbę argumentów, potrzebny byłby dodatkowy sposób określania takich wartości, np. czwarty argument także miał zostać zignorowany.

chodzi o użyteczność, należy rozważyć wiązania element obsługi sygnału z sygnałem:

sig.connect(std::bind(&C::on_sig, this, param, std::placeholders::_1)); 

Jeśli sig ma dodatkowo niepożądanych parametrów emisji, wtedy po prostu zignorowane przez obiekt bind; w przeciwnym razie, wiązanie tego samego programu obsługi z wieloma sygnałami wymagałoby napisania wielu pakietów do przekierowania bez żadnego prawdziwego celu.

+3

"bardziej użyteczne" - debatowałbym o tym. To łamie silne pisanie. A jeśli jest to pożądane, to zachowanie może być nadal emulowane za pomocą ścisłego 'std :: bind' po prostu za pomocą proxy, który akceptuje argumenty variadic. –

+2

@KonradRudolph Wyrażenie wiązania nie * ma * dobrze zdefiniowanego typu w ogólnym przypadku, jeśli jego wywołanie jest funktorem z wieloma 'operator()' s. – ecatmur

+0

Możesz zignorować czwarty argument używając lambda. Ale niezbyt fajne. – dyp

Powiązane problemy