Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Previous revision Next revision | Previous revision | ||
lambda [2008/04/16 22:14] przemo86 |
lambda [2008/04/16 23:27] przemo86 |
||
---|---|---|---|
Linia 18: | Linia 18: | ||
===== Przykłady ===== | ===== Przykłady ===== | ||
Poniższe przykłady pokazują (w niewielkim stopniu) możliwości tych wyrażeń. Należy w tym miejscu zwrócić uwagę, że często wyrażenia lambda wykorzystują mechanizmy pomocnicze zdefiniowane w innych bibliotekach których nagłówki należy dołączyć. Standardowo dołączamy bibliotekę boost\lambda\lambda.hpp. W przykładach będą pokazane nagłówki które dodatkowo należy dołączyć by kod się skompilował. | Poniższe przykłady pokazują (w niewielkim stopniu) możliwości tych wyrażeń. Należy w tym miejscu zwrócić uwagę, że często wyrażenia lambda wykorzystują mechanizmy pomocnicze zdefiniowane w innych bibliotekach których nagłówki należy dołączyć. Standardowo dołączamy bibliotekę boost\lambda\lambda.hpp. W przykładach będą pokazane nagłówki które dodatkowo należy dołączyć by kod się skompilował. | ||
+ | |||
==== Pierwszy rzut oka na boost::lambda ==== | ==== Pierwszy rzut oka na boost::lambda ==== | ||
Linia 34: | Linia 35: | ||
</code> | </code> | ||
- | Kod ten możemy odczytać jako: Wywołaj w tym konkretnym miejscu funkcję którą wyprowadzi na standardowe wyjście argumenty w kolejności 2,1,3. | + | Kod ten możemy odczytać jako: Wywołaj w tym konkretnym miejscu funkcję która wyprowadzi na standardowe wyjście argumenty w kolejności 2,1,3. |
==== Elementy kontenerów ==== | ==== Elementy kontenerów ==== | ||
Linia 50: | Linia 52: | ||
void funkcja_klasy (const float i) const | void funkcja_klasy (const float i) const | ||
{ | { | ||
- | std::cout << "\nvoid example::funkcja_klasy : " << i; | + | std::cout << "\nvoid Example::funkcja_klasy : " << i; |
} | } | ||
Linia 89: | Linia 91: | ||
Example * ex_ptr = &ex; | Example * ex_ptr = &ex; | ||
- | std::cout << "\Uzycie boost::bind dla funkcji globalnych."; | + | std::cout << "Uzycie boost::bind dla funkcji globalnych."; |
std::for_each(vec_test.begin(), vec_test.end(), bind(&funkcja_globalna,_1)); | std::for_each(vec_test.begin(), vec_test.end(), bind(&funkcja_globalna,_1)); | ||
Linia 111: | Linia 113: | ||
using namespace boost::lambda; | using namespace boost::lambda; | ||
- | std::cout << "\n\nUzycie wyrazenia lambda dla obiektow (czy tez wskazan do nich) wprost z std::vector.\n"; | + | std::cout << "Uzycie wyrazenia lambda dla obiektow (czy tez wskazan do nich) wprost z std::vector.\n"; |
std::for_each(vec_test.begin(), vec_test.end(), std::cout << constant("Wyrazenie boost::lambda: ") <<_1 << constant("\n") ); | std::for_each(vec_test.begin(), vec_test.end(), std::cout << constant("Wyrazenie boost::lambda: ") <<_1 << constant("\n") ); | ||
Linia 120: | Linia 122: | ||
Mając przykładowy wektor vec_test chcemy posortować jego elementy malejąco. Dzięki wyrażeniom lambda nie musimy tworzyć obiektów funkcyjnych. Możemy warunek napisać wprost: | Mając przykładowy wektor vec_test chcemy posortować jego elementy malejąco. Dzięki wyrażeniom lambda nie musimy tworzyć obiektów funkcyjnych. Możemy warunek napisać wprost: | ||
- | <code> | + | <code cpp> |
#include <algorithm> | #include <algorithm> | ||
#include <boost/lambda/lambda.hpp> | #include <boost/lambda/lambda.hpp> | ||
Linia 132: | Linia 134: | ||
</code> | </code> | ||
+ | |||
+ | |||
+ | |||
==== Konstrukcje sterujące oraz pętle ==== | ==== Konstrukcje sterujące oraz pętle ==== | ||
+ | Przekazywane do szablonów standardowych algorytmów funkcje są zazwyczaj bardziej skomplikowane. Biblioteka boost::lambda umożliwia standardowe konstrukcje sterujące wymienione poniżej. | ||
+ | === if_else === | ||
+ | <code cpp> | ||
+ | #include <algorithm> | ||
+ | #include <boost/lambda/lambda.hpp> | ||
+ | #include <boost/lambda/if.hpp> | ||
+ | |||
+ | using namespace Boost::lambda; | ||
+ | |||
+ | std::cout << "Uzycie konstrukcji if_else_then(warunek, instrukcje_dla_true, instrukcje_dla_false)." | ||
+ | << "Alternatywnie if_(warunek)[instrukcje_dla_true].else_[instrukcje_dla_false].\n"; | ||
+ | |||
+ | for_each(vec_test.begin(), vec_test.end(), | ||
+ | if_then_else(_1 > 3 , | ||
+ | std::cout << constant("\n(if_then_else) Liczba : ") << _1 << constant( " jest wieksza niz 3!\n") , | ||
+ | std::cout << constant("\n(if_then_else) Liczba : ") << _1 << constant( " jest mniejsza lub rowna 3!\n"))); | ||
+ | </code> | ||
+ | |||
+ | === Switch === | ||
+ | |||
+ | <code cpp> | ||
+ | #include <boost/lambda/lambda.hpp> | ||
+ | #include <boost/lambda/switch.hpp> | ||
+ | |||
+ | using namespace Boost::lambda; | ||
+ | |||
+ | std::cout << "Uzycie konstrukcji switch.\n" ; | ||
+ | (switch_statement( | ||
+ | _1, | ||
+ | case_statement<0> | ||
+ | (std::cout << constant("Wybrales 0 \n")), | ||
+ | case_statement<1> | ||
+ | (std::cout << constant("Wybrales 1 \n")), | ||
+ | default_statement | ||
+ | (std::cout << constant("Nie mam pojecia co wybrales!\n"))) | ||
+ | ) ((make_const(666))); | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Użycie (make_const(666)) jest konieczne. Szablon tej funkcji jest następujący i jest zdefiniowany w bibliotece boost: | ||
+ | <code cpp> | ||
+ | template <class T> inline const T& make_const(const T& t) { return t; } | ||
+ | </code> | ||
+ | Przekazanie samego 666 mogłoby sprowokować błąd ponieważ 666 jest typu int i nie może mieć kwalifikatora const. Szablon natomiast potrzebuje const &. | ||
+ | |||
+ | === Petla while === | ||
+ | |||
+ | <code cpp> | ||
+ | #include <boost/lambda/lambda.hpp> | ||
+ | #include <boost/lambda/loops.hpp> | ||
+ | |||
+ | using namespace Boost::lambda; | ||
+ | |||
+ | std::cout << "Uzycie konstrukcji (while_loop(warunek, instrukcje))(argumenty)\n\n"; | ||
+ | |||
+ | int start = 5; | ||
+ | int end = 10; | ||
+ | (while_loop(_1 <= _2, | ||
+ | (++_1, std::cout << _2 << constant(" - ") << _1 << constant(" = ") << _2 -_1 << constant("\n") ))) | ||
+ | (start,end); | ||
+ | |||
+ | </code> | ||
+ | |||
+ | === Petla do while === | ||
+ | |||
+ | <code cpp> | ||
+ | #include <boost/lambda/lambda.hpp> | ||
+ | #include <boost/lambda/loops.hpp> | ||
+ | |||
+ | using namespace Boost::lambda; | ||
+ | |||
+ | |||
+ | (do_while_loop( _1 == 0 , std::cout << constant ("Uzycie konstrukcji (do_while_loop(warunek, instrukcje))(argumenty).\n")))(make_const(1)); | ||
+ | |||
+ | (do_[ | ||
+ | _1 == 0 , std::cout << constant ("Uzycie konstrukcji (do_[instrukcje].while_(warunek))(argumenty).\n") | ||
+ | ].while_(_1 == 0))(make_const(1)); | ||
+ | </code> | ||
+ | |||
+ | |||
+ | === Petla for === | ||
+ | |||
+ | <code cpp> | ||
+ | #include <boost/lambda/lambda.hpp> | ||
+ | #include <boost/lambda/loops.hpp> | ||
+ | |||
+ | using namespace Boost::lambda; | ||
+ | |||
+ | std::cout << "Uzycie konstrukcji (for_ (war_poczatkowe,warunek, instrukcja iteracji)[instrukcje])(argumenty) : \n"; | ||
+ | int i = 0; | ||
+ | |||
+ | (for_ (var(i)=0 , var(i) < _1, ++var(i)) | ||
+ | [ | ||
+ | var(std::cout) << var(i) << constant("^2 = ") << make_const( var(i)*var(i) ) << constant("\n") | ||
+ | ] | ||
+ | )(make_const (4)); | ||
+ | </code> | ||
+ | |||
+ | Ponieważ powyższe wyrażenie jest wyrażeniem lambda więc aby ono zrozumiało zmienne zewnętrzne należy je stworzyć jego elementem. Taką konwersje tworzy funkcja var(). | ||
+ | |||
+ | |||
+ | ==== Rzutowanie i wyjątki ==== | ||
+ | Biblioteka boost::lambda umożliwia wprowadzenie rzutowania w wyrażeniu lambda jak również genrowanie i przechwytywanie wyjątków. Oto przykład prezentujący konstrukcję: | ||
+ | |||
+ | <code cpp> | ||
+ | #include <boost/lambda/lambda.hpp> | ||
+ | #include <boost/lambda/casts.hpp> | ||
+ | #include <boost/lambda/exceptions.hpp> | ||
+ | |||
+ | struct ExampleDerived : public Example | ||
+ | { | ||
+ | void funkcja_klasy_pochodnej (float i) const | ||
+ | { | ||
+ | std::cout << "void ExampleDerived::funkcja_klasy_pochodnej : " << i << std::endl; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | using namespace Boost::lambda; | ||
+ | |||
+ | ExampleDerived ex_derv; | ||
+ | |||
+ | // Rzutowanie w tym przykładzie nie powiedzie się i zostanie wygenerowany wyjątek, a następnie | ||
+ | // przechwycony i obsłużony. | ||
+ | |||
+ | std::cout << "Uzycie rzutowania i wykorzystanie mechanizmu wyjatkow w wyrazeniach lambda.\n"; | ||
+ | (try_catch( | ||
+ | bind(&example_derived::funkcja_klasy_pochodnej, ll_dynamic_cast<example_derived&>(*_1),_2), | ||
+ | catch_exception<std::bad_cast>(bind(&example::funkcja_klasy,_1,_2))))(ex_ptr, make_const(66.6f)); | ||
+ | |||
+ | std::cout << std::endl; | ||
+ | // Rzutowanie w tym przykładzie powiedzie się. Przedstawiono dodatkowo schemat zapisu przechwytywania | ||
+ | // wyjątków różnych typów oraz dowolonego wyjątku. | ||
+ | |||
+ | (try_catch( | ||
+ | bind(&example_derived::funkcja_klasy_pochodnej, ll_dynamic_cast<example_derived&>(*_1),_2), | ||
+ | catch_exception<std::bad_cast>(bind(&example::funkcja_klasy,_1,_2)), | ||
+ | catch_exception<std::exception>(), | ||
+ | catch_all()))(make_const(&ex_derv), make_const(77.7f)); | ||
+ | |||
+ | </code> | ||
+ | ===== Zakończenie i plik z przykładami ===== | ||
+ | Wyrażenia lambda to przydatne konstrukcje które nie raz mogą zaoszczędzić czas, zmniejszyć ilość kodu czy zajętą przez program pamięć. Mankamentem jest składnia wyrażeń której należy się po prostu nauczyć i przećwiczyć na wielu przykładach. | ||
+ | Powyższe przykłady można wypróbować pobierając plik: | ||
+ | {{boost_lambda.cpp|}} |