Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
bind [2008/04/12 19:24] maciejp |
bind [2008/04/14 08:53] 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'' 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''. |
- | 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 213: | Linia 218: | ||
=====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ów, funkcji. 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 222: | Linia 227: | ||
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===== | ||
Linia 233: | Linia 237: | ||
!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 | ||
Linia 274: | Linia 281: | ||
- | =====Przykład użycia===== | + | |
+ | =====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. | 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. | ||
Linia 317: | Linia 325: | ||
statuses.end(), | statuses.end(), | ||
boost::bind(&status::report, _1)); | boost::bind(&status::report, _1)); | ||
+ | |||
+ | return 0; | ||
} | } | ||
</code> | </code> |