Wiem, czym są funktory i kiedy używać ich z std
algorytmami, ale nie rozumiem, co mówi o nich Stroustrup w C ++ 11 FAQ .
Czy ktoś może wyjaśnić, co std::bind
i std::function
kiedy należy ich używać, i podać przykłady dla początkujących?
źródło
Wiem, czym są funktory i kiedy używać ich z std
algorytmami, ale nie rozumiem, co mówi o nich Stroustrup w C ++ 11 FAQ .
Czy ktoś może wyjaśnić, co std::bind
i std::function
kiedy należy ich używać, i podać przykłady dla początkujących?
std::bind
służy do częściowego zastosowania funkcji .
To znaczy, załóżmy, że masz obiekt funkcji, f
który przyjmuje 3 argumenty:
f(a,b,c);
Potrzebujesz nowego obiektu funkcji, który przyjmuje tylko dwa argumenty, zdefiniowane jako:
g(a,b) := f(a, 4, b);
g
jest "częściowym zastosowaniem" funkcji f
: środkowy argument został już określony i zostały jeszcze dwa.
Możesz użyć, std::bind
aby uzyskać g
:
auto g = bind(f, _1, 4, _2);
Jest to bardziej zwięzłe niż pisanie klasy funktora, aby to zrobić.
Dalsze przykłady znajdują się w artykule, do którego prowadzi łącze. Zwykle używa się go, gdy trzeba przekazać funktor do jakiegoś algorytmu. Masz funkcję lub funktor, który wykonuje prawie to, co chcesz, ale jest bardziej konfigurowalny (tj. Ma więcej parametrów) niż wykorzystuje algorytm. Więc wiążesz argumenty z niektórymi parametrami, a resztę pozostawiasz algorytmowi do wypełnienia:
// raise every value in vec to the power of 7
std::transform(vec.begin(), vec.end(), some_output, std::bind(std::pow, _1, 7));
Tutaj pow
przyjmuje dwa parametry i może podbić do dowolnej potęgi, ale wszystko, na czym nam zależy to podbicie do potęgi 7.
Jako okazjonalne użycie, które nie jest częściową aplikacją funkcji, bind
może również zmienić kolejność argumentów na funkcję:
auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3);
Nie polecam go używać tylko dlatego, że nie podoba ci się API, ale ma on potencjalne praktyczne zastosowania, na przykład, ponieważ:
not2(bind(less<T>, _2, _1));
jest funkcją mniejszą lub równą (zakładając całkowity porządek, bla bla). Ten przykład zwykle nie jest konieczny, ponieważ już istnieje std::less_equal
(używa <=
raczej operatora niż <
, więc jeśli nie są one spójne, możesz tego potrzebować, a także możesz potrzebować odwiedzić autora klasy za pomocą wskazówki). Jest to jednak rodzaj transformacji, która pojawia się, jeśli używasz funkcjonalnego stylu programowania.
myThread=boost::thread(boost::bind(&MyClass::threadMain, this))
std::function
?pow
przykład się nie kompiluje. Ponieważpow
jest to funkcja przeciążona, musisz ręcznie określić, które przeciążenie. Wiązanie nie może pozwolić, aby zostało to wywnioskowane przez wywołującego wynikowy funktor. Np.std::transform(vec.begin(), vec.end(), out.begin(), std::bind((double (*)(double, int))std::pow, _1, 7));
std::bind
pojawia się wraz zthis
użyciem jako drugim argumentem. Czy możesz opisać ten przypadek użycia?std::placeholders::_1
. Zajęło mi trochę czasu, aby dowiedzieć się, dlaczego to się nie kompiluje.Jednym z głównych zastosowań std :: function i std :: bind są bardziej uogólnione wskaźniki funkcji. Możesz go użyć do zaimplementowania mechanizmu wywołania zwrotnego. Jednym z popularnych scenariuszy jest to, że masz jakąś funkcję, której wykonanie zajmie dużo czasu, ale nie chcesz czekać na jej powrót, możesz uruchomić tę funkcję w oddzielnym wątku i nadać jej wskaźnik funkcji, który będzie wywołanie zwrotne po jego zakończeniu.
Oto przykładowy kod, jak tego używać:
źródło
std :: bind został wybrany do biblioteki po propozycji włączenia boost bind, przede wszystkim jest to częściowa specjalizacja funkcji, w której możesz naprawić kilka parametrów i zmienić inne w locie. Teraz jest to biblioteczny sposób robienia lambd w C ++. Jak odpowiedział Steve Jessop
Teraz, gdy C ++ 11 obsługuje funkcje lambda, nie czuję już pokusy, by używać std :: bind. Wolałbym używać curry (częściowa specjalizacja) z funkcją językową niż biblioteką.
Obiekty std :: function są funkcjami polimorficznymi. Podstawową ideą jest możliwość wymiennego odwoływania się do wszystkich wywoływalnych obiektów.
Aby uzyskać więcej informacji, chciałbym wskazać te dwa linki:
Funkcje lambda w C ++ 11: http://www.nullptr.me/2011/10/12/c11-lambda-having-fun-with-brackets/#.UJmXu8XA9Z8
Jednostka wywoływalna w C ++: http://www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8
źródło
std::bind
nigdy nie istniało bez lambd - obie te funkcje zostały wprowadzone w C ++ 11. Mieliśmy,bind1st
abind2nd
które były wychudzonymi wersjami wiązania C ++ 11.Użyłem go dawno temu do stworzenia puli wątków wtyczek w C ++; Ponieważ funkcja przyjmowała trzy parametry, możesz pisać w ten sposób
Załóżmy, że Twoja metoda ma podpis:
Aby utworzyć obiekt funkcji do powiązania trzech parametrów, możesz zrobić w ten sposób
Teraz, aby powiązać parametry, musimy napisać funkcję binder. A więc oto jest:
I funkcja pomocnicza do używania klasy binder3 - bind3:
a tutaj nas, jak to nazwać
Uwaga: f3 (); wywoła metodę task1-> ThreeParameterTask (21,22,23);
Aby uzyskać więcej szczegółów -> http://www.codeproject.com/Articles/26078/AC-Plug-in-ThreadPool-Design
źródło