Narzędzia użytkownika

Narzędzia witryny


bind

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Previous revision
Next revision
Previous revision
bind [2008/04/12 19:24]
maciejp
bind [2008/04/14 09:00] (aktualna)
maciejp
Linia 1: Linia 1:
 ======Biblioteka Boost.Bind====== ======Biblioteka Boost.Bind======
  
-Funkcja boost::bind jest generalizacją funkcji std::​bind1st i std::​bind2nd dostępnych w bibliotece standardowej. Funkcja ta wspiera funktory, funkcje, wskaźniki do funkcji oraz wskaźniki do funkcji składowych. Jest w stanie związać dowolny argument ze specyficzną wartością albo przekierować argumenty wejściowe we wskazane pozycje. boost::bind nie nakłada żadnych wymagań obiektom funkcyjnym, w ogólności nie wymaga standardowych definicji typów takich jak: result_type,​ first_argument_type,​ second_argument_type. +Funkcja ​''​boost::bind'' ​jest generalizacją funkcji ​''​std::​bind1st'' ​''​std::​bind2nd'' ​dostępnych w bibliotece standardowej. Funkcja ta wspiera funktory, funkcje, wskaźniki do funkcji oraz wskaźniki do funkcji składowych. Jest w stanie związać dowolny argument ze specyficzną wartością albo przekierować argumenty wejściowe we wskazane pozycje. ​''​boost::bind'' ​nie nakłada żadnych wymagań obiektom funkcyjnym, w ogólności nie wymaga standardowych definicji typów takich jak: ''​result_type''​''​first_argument_type''​''​second_argument_type''​
-Do korzystania z funcji boost::bind konieczne jest dołączenie nagłówka ​boost/​bind.hpp. +Do korzystania z funcji boost::bind konieczne jest dołączenie nagłówka ​''​boost/​bind.hpp''​.
- +
  
  
Linia 24: Linia 22:
 </​code>​ </​code>​
  
-Najprostszym przypadkiem użycia boost::bind jest stworzenie bezargumentowego funktora przez zastąpienie argumentów funkcji wartościami stałymi.+Najprostszym przypadkiem użycia ​''​boost::bind'' ​jest stworzenie bezargumentowego funktora przez zastąpienie argumentów funkcji wartościami stałymi.
  
 <code cpp> <code cpp>
Linia 30: Linia 28:
 </​code>​ </​code>​
  
-Jako pierwszy argument boost::bind podajemy wskaźnik do funkcji, następne ​argumenty ​przypisywane są jako pierwszy i drugi argument funkcji g. Typ zwracany przez funktor jest identyczny z typem zwracanym przez funkcję podaną jako pierwszy argument.+Jako pierwszy argument ​''​boost::bind'' ​podajemy wskaźnik do funkcji, następne ​dwa przypisywane są jako pierwszy i drugi argument funkcji ​''​g''​. Typ zwracany przez funktor jest identyczny z typem zwracanym przez funkcję podaną jako pierwszy argument.
 Znacznie ciekawszym mechanizmem jest możliwość selektywnego zastępowania argumentów lub kolejności przekazywanych argumentów. Znacznie ciekawszym mechanizmem jest możliwość selektywnego zastępowania argumentów lub kolejności przekazywanych argumentów.
  
Linia 36: Linia 34:
 int main() { int main() {
   int i1=1,​i2=2,​i3=3,​i4=4,​i5=5,​i6=6,​i7=7,​i8=8,​i9=9;​   int i1=1,​i2=2,​i3=3,​i4=4,​i5=5,​i6=6,​i7=7,​i8=8,​i9=9;​
-  ​(boost::​bind(&​nine_arguments,​_9,​_2,​_1,​_6,​_3,​_8,​_4,​_5,​_7))  ​//​utworzenie tymczasowego funktora i wywołanie +  boost::​bind(f,​_9,​_2,​_1,​_6,​_3,​_8,​_4,​_5,​_7) ​          ​//​utworzenie tymczasowego funktora i wywołanie 
-    (i1,​i2,​i3,​i4,​i5,​i6,​i7,​i8,​i9); ​                           //​odpowiadające wywołaniu f(i9, i2, i1, i6, i3, i8, i4, i5, i7) +    (i1,​i2,​i3,​i4,​i5,​i6,​i7,​i8,​i9); ​                    ​//​odpowiadające wywołaniu f(i9, i2, i1, i6, i3, i8, i4, i5, i7) 
-                                                             ​//w wyniku otrzymamy ciąg: 921638457 +                                                      //w wyniku otrzymamy ciąg: 921638457 
-+  ​return ​0; 
-bind(f, _2, _3, _1, _1, 0, 0, _3, 0, _2)(x, y, z) //​utworzenie tymczasowego funktora i wywołanie +}                                               
-                                                    +
 </​code>​ </​code>​
  
-Realizujemy to za pomocą symbli zastępczych oznaczanych jako _1, _2, ..., _9. Dostępnych mamy łacznie 9 takich symboli. Ogranicza to możliwośc tworzenia funktorów do funktorów 9 elementowych (w przypadku funkcji składowych jest to 8 argumentów;​ musimy pamietć o przekazaniu obiektu na rzecz, którego będzie wywoływany funktor). Symbol _1 oznacza "​zastąp przez pierwszy argument wejściowy",​ analogicznie pozostałe osiem. +Realizujemy to za pomocą symbli zastępczych oznaczanych jako ''​_1''​''​_2''​, ..., ''​_9''​. Dostępnych mamy łacznie 9 takich symboli. Ogranicza to możliwośc tworzenia funktorów do funktorów 9 elementowych (w przypadku funkcji składowych jest to 8 argumentów;​ musimy pamietć o przekazaniu obiektu na rzecz, którego będzie wywoływany funktor). Symbol ​''​_1'' ​oznacza "​zastąp przez pierwszy argument wejściowy",​ analogicznie pozostałe osiem. 
-Jak wynika z przykładu, ​można dowolnie ​"​mieszać" argumenty ​ze stałymi jak i ich kolejność.+Argumenty ​można dowolnie ​zamieniać ze stałymi jak i zamieniać ​ich kolejność. 
 + 
  
 =====Użycie z funktorami===== =====Użycie z funktorami=====
  
-boost::bind nie jest ograniczony tylko do funkcji, akceptuje min. również funktory. W przypadku użycia funktora zazwyczaj ​trzeba ​jawnie podać typ zwracany przez operator() funktora (ewentualnie zdefinjować typ result_type w funktorze).+''​boost::bind'' ​nie jest ograniczony tylko do wskaźników ​do funkcji, akceptuje min. również funktory. W przypadku użycia funktora zazwyczaj ​należy ​jawnie podać typ zwracany przez ''​operator()'' ​funktora (ewentualnie zdefinjować typ ''​result_type'' ​w funktorze).
  
 <code cpp> <code cpp>
Linia 65: Linia 64:
 </​code>​ </​code>​
  
-Niektóre kompilatory mają problem ze składnią w postaci bind<​R>​(...). Wyrażenie to można zastąpić postacią alternatwną.+Niektóre kompilatory mają problem ze składnią w postaci ​''​bind<​R>​(...)''​. Wyrażenie to można zastąpić postacią alternatwną.
  
 <code cpp> <code cpp>
 boost::​bind(boost::​type<​int>​(),​ f, _1, _1)(x); boost::​bind(boost::​type<​int>​(),​ f, _1, _1)(x);
 </​code>​ </​code>​
 +
 +
 +
  
  
 =====Użycie ze wskaźnikami do składowych===== =====Użycie ze wskaźnikami do składowych=====
  
-Wskaźniki do metod i danych sładowych nie są obiektami funkcyjnymi,​ ponieważ nie wspierają operatora operator(). Dla wygody boost::bind akceptuje te wskażniki jako pierwszy argument. boost::bind używa funkcji boost::​mem_fn do przekonwertowania ​wskźników do składowych na funktory. Innymi słowy, wyrażenie:+Wskaźniki do metod i danych sładowych nie są obiektami funkcyjnymi,​ ponieważ nie wspierają operatora ​''​operator()''​. Dla wygody ​''​boost::bind'' ​akceptuje te wskażniki jako pierwszy argument. ​''​boost::bind'' ​używa funkcji ​''​boost::​mem_fn'' ​do konwersji ​wskźników do składowych na funktory. Innymi słowami, wyrażenie:
  
 <code cpp> <code cpp>
Linia 86: Linia 88:
 </​code>​ </​code>​
  
-gdzie R jest typem zwracanym przez Foo::f w przypadku metod lub typem danych w przypadku danych składowych.+gdzie ''​R'' ​jest typem zwracanym przez ''​Foo::f'' ​w przypadku metod lub typem danych w przypadku danych składowych.
  
 Przykład: Przykład:
Linia 106: Linia 108:
 </​code>​ </​code>​
  
-Jako drugi argument boost::bind przekazujemy obiekt klasy na rzecz, której ma być wywoływana funkcja (jest to oczywiste, jeśli zauważymy, że pierwszym niejawnym argumentem metod jest zawsze wskaźnik this - adres obiektu). Najciekawsze są dwie ostatnie linijki przykładu. bind(&​Foo::​f,​ x, _1) przechowuje wewnętrzną kopję obieku x (warto zwrócić na to uwagę, szczególnie gdy kopjowanie obiektu jest kosztowne), natomiast bind(&​Foo::​f,​ p, _1) kopję wskażnika p (p jest sprytnym wskaźnikiem shared_ptr<>​),​ tworzony obiekt funkcyjny przechowuje swoją referencję do instancji klasy Foo i będzie ona poprawna nawet kiedy p wyjdzie poza zasięg lub wykonamy na p reset().+Jako drugi argument ​''​boost::bind'' ​przekazujemy obiekt klasy na rzecz, której ma być wywoływana funkcja (jest to oczywiste, jeśli zauważymy, że pierwszym niejawnym argumentem metod jest zawsze wskaźnik this - adres obiektu). Najciekawsze są dwie ostatnie linijki przykładu. ​''​bind(&​Foo::​f,​ x, _1)'' ​przechowuje wewnętrzną kopję obieku ​''​x'' ​(warto zwrócić na to uwagę, szczególnie gdy kopjowanie obiektu jest kosztowne), natomiast ​''​bind(&​Foo::​f,​ p, _1)'' ​kopję wskażnika ​''​p'' ​(''​p'' ​jest sprytnym wskaźnikiem ​''​shared_ptr<>​''​), tworzony obiekt funkcyjny przechowuje swoją referencję do instancji klasy Foo i będzie ona poprawna nawet kiedy p wyjdzie poza zasięg lub wykonamy na ''​p reset()''​.
  
-Funcję boost::bind można też bezprolemowo użyć z funkcjami wirtualnymi.+Funcję ​''​boost::bind'' ​można też bezprolemowo użyć z funkcjami wirtualnymi.
  
 <code cpp> <code cpp>
Linia 131: Linia 133:
   base* bp = &d;   base* bp = &d;
  
-boost::​bind(&​base::​print,​ _1)(b); +  ​boost::​bind(&​base::​print,​ _1)(b); 
-boost::​bind(&​base::​print,​ _1)(bp); +  boost::​bind(&​base::​print,​ _1)(bp); 
-boost::​bind(&​base::​print,​ _1)(d);+  boost::​bind(&​base::​print,​ _1)(d); 
 + 
 +  return 0; 
 +}
 </​code>​ </​code>​
  
Linia 143: Linia 148:
 derived! derived!
 </​code>​ </​code>​
 +
  
  
 =====Użycie zagnieżdżeń do kompozycji fukcji===== =====Użycie zagnieżdżeń do kompozycji fukcji=====
  
-Część argumentów przekazywanych bind może być zagnieżdżonymi wyrażeniami boost::​bind.+Część argumentów przekazywanych bind może być zagnieżdżonymi wyrażeniami ​''​boost::bind''​.
  
 <code cpp> <code cpp>
Linia 153: Linia 159:
 </​code>​ </​code>​
  
-Wewnętrzne wyrażenia są ewaluowane w bliżej nie okreśłonej kolejności,​ ale przed wywołaniem funktora zewnętzrnego boost::​bind. Odnosząc się do przykładu, kiedy utworzony funktor jest wywoływany z argumentem x, w pierwszej kolejności ewalowany jest bind(g, _1)(x), dając g(x), następnie bind(f, g(x))(x), dając finalny wynik w postaci wywołania f(g(x)).+Wewnętrzne wyrażenia są ewaluowane w bliżej nie okreśłonej kolejności,​ ale przed wywołaniem funktora zewnętzrnego ​''​boost::bind''​. Odnosząc się do przykładu, kiedy utworzony funktor jest wywoływany z argumentem ​''​x''​, w pierwszej kolejności ewalowany jest ''​bind(g, _1)(x)''​, dając ​''​g(x)''​, następnie ​''​bind(f, g(x))(x)''​, dając finalny wynik w postaci wywołania ​''​f(g(x))''​.
  
-Ta cecha boost::bind może być bardzo dobrze zastosowana do kompozycji funkcji.+Ta cecha ''​boost::bind'' ​może być bardzo dobrze zastosowana do kompozycji funkcji.
  
-Trzeba zaznaczyć, że pierwszy argument boost::bind (opakowywany obiekt funkcyjny) nie jest ewalowany, nawet wtedy, kiedy jest to obiekt funkcyjny produkowany przez zagnieżdżone wywołanie bind lub argument w postaci ​ symbola zastępczego. Poniższy przykład nie będzie działał tak, jakbyśmy tego oczekiwali.+Trzeba zaznaczyć, że pierwszy argument ​''​boost::bind'' ​(opakowywany obiekt funkcyjny) nie jest ewalowany, nawet wtedy, kiedy jest to obiekt funkcyjny produkowany przez zagnieżdżone wywołanie ​''​bind'' ​lub argument w postaci ​ symbola zastępczego. Poniższy przykład nie będzie działał tak, jakbyśmy tego oczekiwali.
  
 <code cpp> <code cpp>
Linia 167: Linia 173:
 </​code>​ </​code>​
  
-Oczekiwany efekt uzyskamy korzystając z pomocniczego obiektu funkcyjnego apply (implementacja apply w boost/​bind/​apply.hpp),​ który podajemy jako pierwszy argument boost::​bind. Poprzedni przykład powinien wyglądać następująco.+Oczekiwany efekt uzyskamy korzystając z pomocniczego obiektu funkcyjnego ​''​apply'' ​(implementacja ​''​apply'' ​''​boost/​bind/​apply.hpp''​), który podajemy jako pierwszy argument ​''​boost::bind''​. Poprzedni przykład powinien wyglądać następująco.
  
 <code cpp> <code cpp>
Linia 177: Linia 183:
 </​code>​ </​code>​
  
-Używając bind można komponować funkcje korzystając naraz z boost::bind i funkcji (algorytmów) z biblioteki standardowej.+Używając ​''​bind'' ​można komponować funkcje korzystając naraz z ''​boost::bind'' ​i funkcji (algorytmów) z biblioteki standardowej.
  
 <code cpp> <code cpp>
Linia 209: Linia 215:
 </​code>​ </​code>​
  
-Jak widać na przykładzie łatwo można tworzyć złożone predykaty. Często trzeba się jednak często zastanowić,​ czy stosować bardzo złożone wyrażenia. Utrudniają one późniejszą analizę kodu, często wręcz uniemożliwiają. Warto rozważyć w takich przypadkach zdefinjowanie funktora lub operatora operator() dla klasy.+Jak widać na przykładzie łatwo można tworzyć złożone predykaty. Często trzeba się jednak często zastanowić,​ czy stosować bardzo złożone wyrażenia. Utrudniają one późniejszą analizę kodu, często wręcz uniemożliwiają. Warto rozważyć w takich przypadkach zdefinjowanie funktora lub operatora ​''​operator()'' ​dla klasy. 
  
 =====Użycie z biblioteką Boost.Function===== =====Użycie z biblioteką Boost.Function=====
  
-Funktor zwracany przez boost::bind można przypisać do obiektu funkcyjnego boos::​function. W ten sposób można mięzy innymi przechowywć wcześniej utworzone fukntory ​lub przekazywać je jako argument do konstruktorówfunkcji. Przypisania możemy dokonać wykłym operatorem =.+Funktor zwracany przez ''​boost::bind'' ​można przypisać do obiektu funkcyjnego ​''​boos::​function''​. W ten sposób można między innymi przechowywć wcześniej utworzone fukntory ​jako zmienne i pola klasy albo przekazywać je jako argument do konstruktorów ​lub funkcji. Przypisania możemy dokonać wykłym operatorem ​''​=''​.
  
 <code cpp> <code cpp>
Linia 221: Linia 228:
 </​code>​ </​code>​
  
-Warunkiem poprawnej kompilacji jest dokładne określenie typu szablonu obiektu function (zasada działania boost::​function wykracza poza ten artykuł).+Warunkiem poprawnej kompilacji jest dokładne określenie typu szablonu obiektu function (zasada działania ​''​boost::​function'' ​wykracza poza ten artykuł).
  
  
 =====Przeciążone operatory===== =====Przeciążone operatory=====
  
-Przeciązone operatory dla boost::bind pojawiły się w Boost 1.33+Przeciązone operatory dla ''​boost::bind'' ​pojawiły się w Boost 1.33
  
-Obiekty funkcyjne produkowane przez boost::bind przeciążają logiczny operator przecenia ! oraz operatory relacji ==, !=, <, <=, >, >=.+Obiekty funkcyjne produkowane przez ''​boost::bind'' ​przeciążają logiczny operator przecenia ​''​!'' ​oraz operatory relacji ​''​==''​''​!=''​''​<''​''​<=''​''​>''​''​>=''​.
  
 <​code>​ <​code>​
 !bind(f, ...) !bind(f, ...)
 </​code>​ </​code>​
 +
 Jest ekwiwalentem Jest ekwiwalentem
 +
 <code cpp> <code cpp>
 bind(logical_not(),​ bind(f, ...)) bind(logical_not(),​ bind(f, ...))
 </​code>​ </​code>​
-gdzie logical_not jest funktorem przyjmującym jeden argument x i zwracający !x.+ 
 +gdzie ''​logical_not'' ​jest funktorem przyjmującym jeden argument ​''​x'' ​i zwracający ​''​!x''​.
  
 <code cpp> <code cpp>
 bind(f, ...) op x bind(f, ...) op x
-<​code>​ +</code> 
-op jest operatorem relacji, wyrażniu temu odpowiada+''​op'' ​jest operatorem relacji, wyrażniu temu odpowiada
  
 <code cpp> <code cpp>
 bind(relation(),​ bind(f, ...), x) bind(relation(),​ bind(f, ...), x)
 </​code>​ </​code>​
-gdzie relation jest funktorem przyjmującym dwa argumenty a i b zwracającym a op b.+gdzie ''​relation'' ​jest funktorem przyjmującym dwa argumenty ​''​a'' ​''​b''​ oraz zwracającym ​''​a op b''​.
  
-Przeciążenie tych operatorów umożliwia na konwencjonalne negowanie wyniku boost::​bind:​+Przeciążenie tych operatorów umożliwia na konwencjonalne negowanie wyniku ​''​boost::bind''​:
  
 <code cpp> <code cpp>
Linia 255: Linia 265:
 </​code>​ </​code>​
  
-oraz na porównywanie wyników boost::bind z wartościami:​+oraz na porównywanie wyników ​''​boost::bind'' ​z wartościami:​
  
 <code cpp> <code cpp>
Linia 267: Linia 277:
 </​code>​ </​code>​
  
-albo z innym wyrażeniem boost::​bind:​+albo z innym wyrażeniem ​''​boost::bind''​:
  
 <code cpp> <code cpp>
Linia 274: Linia 284:
  
  
-=====Przykład użycia===== 
  
-boost::bind umożliwia w przeciwnieństwie do funkcji z biblioteki standardowej (służących do tworzenia adpterów funkcji) bardzo elastyczną pracę z kodem.+ 
 +=====Inny przykład użycia===== 
 + 
 +''​boost::bind'' ​umożliwia w przeciwnieństwie do funkcji z biblioteki standardowej (służących do tworzenia adpterów funkcji) bardzo elastyczną pracę z kodem.
  
 <code cpp> <code cpp>
Linia 317: Linia 329:
     statuses.end(),​     statuses.end(),​
     boost::​bind(&​status::​report,​ _1));     boost::​bind(&​status::​report,​ _1));
 +
 +  return 0;
 } }
 </​code>​ </​code>​
Linia 334: Linia 348:
 </​code>​ </​code>​
  
-Użycie funkcji standardowych (std::​mem_fun_ref i std::​mem_fun) zmusza do zmian także pętli for_each po każdej modyfikacji typu przechowywanego przez wektor, a nawet uniemożliwia dalszą pracę (brak obsługi w przypadku użycia sprytnych wskaźników).+Użycie funkcji standardowych (''​std::​mem_fun_ref'' ​''​std::​mem_fun''​) zmusza do zmian także pętli ​''​for_each'' ​po każdej modyfikacji typu przechowywanego przez wektor, a nawet uniemożliwia dalszą pracę (brak obsługi w przypadku użycia sprytnych wskaźników).\\ 
 +\\ 
 +\\ 
 + --- //​[[mplachta@stud.elka.pw.edu.pl|Maciej Płachta H1ISI]]//
bind.1208021071.txt.gz · ostatnio zmienione: 2008/04/12 19:24 przez maciejp