Narzędzia użytkownika

Narzędzia witryny


lambda

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
lambda [2008/04/16 22:14]
przemo86
lambda [2008/04/16 23:27] (aktualna)
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|}}
lambda.1208376846.txt.gz · ostatnio zmienione: 2008/04/16 22:14 przez przemo86