Narzędzia użytkownika

Narzędzia witryny


tuple

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
tuple [2008/04/01 00:18]
zegadlor
tuple [2008/04/13 11:19] (aktualna)
zegadlor
Linia 1: Linia 1:
 ======Biblioteka Boost Tuple====== ======Biblioteka Boost Tuple======
  
-Czasem w czasie pisania kodu zachodzi potrzeba zgrupowania kilku obiektów w jeden. Biblioteka standardowa implementuje szablon std::pair, który potrafi zgrupować dwa obiekty. Wraz z szablonem funkcji std::​make_pair i operatorami porównywania szablon ten tworzy dość przydatne programiście narzędzie. Co w momencie gdy potrzebujemy takiego narzędzia do zgrupowania 3 i więcej wartości? Możemy pokusić się o napisanie własnej klasy bądź szablonu klas grupującego obiekty. O wiele wygodniej jednak skorzystać z gotowego rozwiązania jakie oferuje nam biblioteka Boost Tuple. Oferuje ona szablon boost::​tuple pozwalający agregować do 10 elementów.+Czasem w czasie pisania kodu zachodzi potrzeba zgrupowania kilku obiektów w jeden. Biblioteka standardowa implementuje szablon std::pair, który potrafi zgrupować dwa obiekty. Wraz z szablonem funkcji std::​make_pair i operatorami porównywania szablon ten tworzy dość przydatne programiście narzędzie. Co w momencie gdy potrzebujemy takiego narzędzia do zgrupowania 3 i więcej wartości? Możemy pokusić się o napisanie własnej klasy bądź szablonu klas grupującego obiekty. O wiele wygodniej jednak skorzystać z gotowego rozwiązania jakie oferuje nam biblioteka Boost Tuple. Oferuje ona szablon boost::​tuple pozwalający agregować do 10 elementów ​(tworząc tzw. krotki).
  
 =====Tworzenie krotek===== =====Tworzenie krotek=====
Linia 39: Linia 39:
 boost::​make_tuple(10,​ "Moja krotka",​ 10.5); ​ //Tworzy krotkę na podstawie dedukcji typów boost::​make_tuple(10,​ "Moja krotka",​ 10.5); ​ //Tworzy krotkę na podstawie dedukcji typów
 </​code>​ </​code>​
- + 
 +=====Wiązanie samodzielnych elementów w krotki===== 
 +Ciekawym mechanizmem biblioteki Tuples jest możliwość wiązania pojedynczych wartości w krotki. Służy do tego szablon funkcji tie. Elementy krotki utworzonej przez tie są modyfikowalnymi referencjami odpowiednich wartości. 
 +<code cpp> 
 +int i; char c; double d; 
 +boost::​tie(i,​ c, d) = make_tuple(1,'​a',​ 5.5);  //​Powiązanie pojedynczych wartości w krotkę 
 +std::cout << i << " " << ​ c << " " << d;  //Wynik to 1 a 5.5 
 +</​code>​ 
 +Powyższy przykład prezentuje jedno z ważnych zastosowań krotek - możemy je wykorzystywać do zwracania wielu wartości z funkcji. 
 + 
 +Jeśli w przypisaniu chcemy pominąć którąś pozycję krotki używamy obiektu ignore. Poniższy przykład pokazuje, że funkcja tie współpracuje także z obiektami klasy pair z biblioteki standardowej. 
 +<code cpp> 
 +int i; 
 +/* Zmień wartość tylko i. Wartość krotki pod indeksem 0 jest ignorowana. */ 
 +boost::​tie(boost::​tuples::​ignore,​ i) = std::​make_pair("​Krotka",​ 1); 
 +</​code>​ 
 +Moglibyśmy po prostu pominąć wartość pod indeksem 0. Jawne ignorowanie może być jednak pomocne dla kogoś, kto w przyszłości będzie edytował nasz kod. W ten sposób od razu widać, że wartość nie jest pominięta przez przypadek. 
 =====Dostęp do elementów krotki===== =====Dostęp do elementów krotki=====
 Dostęp do elementów krotek możliwy jest dzięki metodzie get klasy tuple lub zewnętrznej wobec klasy funkcji get. Obie wymagają konkretyzacji indeksem elementu (oczywiście liczonym od zera). Obie też zwracają referencję do obiektu znajdującego się pod podanym indeksem. Dostęp do elementów krotek możliwy jest dzięki metodzie get klasy tuple lub zewnętrznej wobec klasy funkcji get. Obie wymagają konkretyzacji indeksem elementu (oczywiście liczonym od zera). Obie też zwracają referencję do obiektu znajdującego się pod podanym indeksem.
Linia 54: Linia 71:
 std::​cout<<​foo.get<​5>​(); ​ //Błąd kompilacji. Rozmiar krotki 3. std::​cout<<​foo.get<​5>​(); ​ //Błąd kompilacji. Rozmiar krotki 3.
 </​code>​ </​code>​
- 
-Użycie zewnętrznej funkcji zamiast metody klasy uzależnia nasz kod od konkretnych nazw obiektów co może być niepożądane w rozwiązaniach uogólnionych. 
  
 =====Przypisywanie i kopiowanie krotek===== =====Przypisywanie i kopiowanie krotek=====
Linia 100: Linia 115:
 B b; B b;
 boost::​tuple<​A&>​ ta(b); boost::​tuple<​A&>​ ta(b);
-ta.get<​0>​().fun(); ​ //Wypisze "​a"​. Zachowaliśmy polimorfizm.+std::​cout<<​ta.get<​0>​().fun(); ​ //Wypisze "​a"​. Zachowaliśmy polimorfizm.
 </​code>​ </​code>​
  
Linia 106: Linia 121:
  
 Aby porównywać krotki niezbędne jest włączenie do programu nagłówka "​boost/​tuple/​tuple_comparison.hpp"​. Porównywać możemy tylko krotki o takim samym rozmiarze i jeśli dla odpowiadających elementów są zdefiniowane odpowiednie porównania. Porównanie realizowane są poprzez wywoływanie odpowiednich operatorów parami dla kolejnych obiektów pod odpowiadającymi sobie indeksami. Porównywanie kolejnych par przerywane jest gdy można już ustalić wynik porównania. Operator == zwraca true jeśli wszystkie porównania dla par zwróciły true. Operator != zwraca false gdy chodziaż jedno z porównań zwróciło false. Reszta operatorów realizuje porównania [[http://​pl.wikipedia.org/​wiki/​Porz%C4%85dek_leksykograficzny|leksykograficzne]]. Aby porównywać krotki niezbędne jest włączenie do programu nagłówka "​boost/​tuple/​tuple_comparison.hpp"​. Porównywać możemy tylko krotki o takim samym rozmiarze i jeśli dla odpowiadających elementów są zdefiniowane odpowiednie porównania. Porównanie realizowane są poprzez wywoływanie odpowiednich operatorów parami dla kolejnych obiektów pod odpowiadającymi sobie indeksami. Porównywanie kolejnych par przerywane jest gdy można już ustalić wynik porównania. Operator == zwraca true jeśli wszystkie porównania dla par zwróciły true. Operator != zwraca false gdy chodziaż jedno z porównań zwróciło false. Reszta operatorów realizuje porównania [[http://​pl.wikipedia.org/​wiki/​Porz%C4%85dek_leksykograficzny|leksykograficzne]].
 +
  
 =====Operacje wejścia-wyjścia dla krotek===== =====Operacje wejścia-wyjścia dla krotek=====
Linia 116: Linia 132:
 std::​cout<<"​Wprowadź wartość krotki w formacie (element1 element2)"<<​std::​endl;​ //​Standardowy format strumienia dla krotek std::​cout<<"​Wprowadź wartość krotki w formacie (element1 element2)"<<​std::​endl;​ //​Standardowy format strumienia dla krotek
 std::​cin>>​foo; ​ //Wczytanie krotki ze strumienia wejściowego std::​cin>>​foo; ​ //Wczytanie krotki ze strumienia wejściowego
-std::cout << boost::​tuples::​set_open('​['​) ​     //Ustaw znak początku krotki+std::cout << boost::​tuples::​set_open('​['​) ​\    ​//Ustaw znak początku krotki
           <<​boost::​tuples::​set_close('​]'​) \    //Ustaw znak końca krotki           <<​boost::​tuples::​set_close('​]'​) \    //Ustaw znak końca krotki
    <<​boost::​tuples::​set_delimiter(':'​);​ //Ustaw znak oddzielający elementy krotki    <<​boost::​tuples::​set_delimiter(':'​);​ //Ustaw znak oddzielający elementy krotki
Linia 122: Linia 138:
 std::​cout<<​foo; ​ //Wypisze [1:2.3] zgodnie z tym co ustawiliśmy powyżej std::​cout<<​foo; ​ //Wypisze [1:2.3] zgodnie z tym co ustawiliśmy powyżej
 </​code> ​ </​code> ​
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
  
  
Linia 137: Linia 143:
 =====Ciekawostki===== =====Ciekawostki=====
  
 +===przestrzeń nazw boost::​tuples===
 +W powyższych przykładach zawsze poprzedzaliśmy funkcje z biblioteki kwalifikatorem nazw boost lub boost::​tuples. Uzyskiwaliśmy w ten sposób dostęp do funkcji z następującej hierarchii przestrzeni nazw.
 +<code cpp>
 +namespace boost
 +{
 +  namespace tuples
 +  {
 +    //Pełny kod biblioteki
 +  }
 +  ​
 +  //Funkcje dostępne bezpośrednio z przestrzeni nazw boost
 +  using tuples::​tuple; ​
 +  using tuples::​make_tuple;​
 +  using tuples::​tie;​
 +  using tuples::​get;​
 +}
 +</​code>​
  
 +===make_tuple i dedukcja typów===
  
 +make_tuple w czasie tworzenia nowych krotek domyślnie określa argumenty jako niereferencyjne i modyfikowalne. Co w momencie gdy nie jest to zachowanie pożądane? Z pomocą przychodzi nam inna biblioteka Boost - Boost Ref. Z wykorzystaniem funkcji ref możemy za pomocą make_tuple utworzyć krotkę składającą się z referencji lub referencji const ( funkcja cref).
  
 +<code cpp>
 +/* Standardowe działanie. Tworzy krotkę o typie typach int, int. */
 +boost::​tuples::​make_tuple(10,​ 20);
  
 +/* Dzięki użyciu funkcji ref tworzy krotkę int&, int. */
 +boost::​tuples::​make_tuple(boost::​ref(10),​ 20);
  
 +/*Typ pierwszego elementu to const int&. Modyfikację działania make_tuple uzyskujemy dzięki użyciu funkcji cref*/
 +boost::​tuple<​const int&, int> foo = boost::​tuples::​make_tuple(boost::​cref(10),​ 20);  //OK
  
 +boost::​tuple<​int&,​ int> foo = boost::​tuples::​make_tuple(boost::​cref(10),​ 20);  //Bład kompilacji
 +</​code>​
  
 +===krotki w kontenerach sekwencyjnych===
 +Czasem trzymając krotki w kontenerach sekwencyjnych zachodzi potrzeba posortowania ich według jednego z elementów krotek. Możemy wtedy zdefiniować pomocniczy szablon klasy.
  
 +<code cpp>
 +template<​int Index> class Comparator
 +{
 +  public:
 +    template<​typename Tuple>
 +    bool operator()(const Tuple& tuple_a, const Tuple& tuple_b) const
 +    {
 +      return boost::​get<​Index>​(tuple_a)<​boost::​get<​Index>​(tuple_b);​
 +    }
 +}
 +</​code>​
  
 +Korzystając z obiektu funkcyjnego powyższej klasy sortowanie możemy zrealizować następująco.
  
 +<code cpp>
 +/* Niezbędne nagłówki. */
 +#include <​iostream>​
 +#include <​vector>​
 +#include "​boost/​tuple/​tuple.hpp"​
  
-  Do korzystania z operacji wejścia-wyjścia na krotkach niezbędne jest dołączenie "boost/tuple/tuple_io.hpp"​. ​Podział biblioteki Tuple minimalizuje czas kompilacjiJeśli nie potrzebujemy operatorów relacyjnych czy operacji wejścia-wyjścia nie ponosimy kosztu ich kompilacji.+int main(int argc, char** argv) 
 +
 +  typedef ​boost::tuple<int, double, std::​string>​ my_tuple_t;  ​//Dla poprawienia czytelności kodu 
 +  std::​vector<​my_tuple_t>​ v;  //Tworzymy vector 
 +  
 +  v.push_back(my_tuple_t(1,​ 2.0, "Pierwsza krotka"​)); ​ //Dodajemy do vectora 3 różne krotki 
 +  v.push_back(my_tuple_t(2,​ 1.0, "Druga krotka"​));​ 
 +  v.push_back(my_tuple_t(3,​ 3.0, "​Trzecia krotka"​));​
  
 +  std::​sort(v.begin(),​ v.end(), Comparator<​1>​()); ​ //Sortujemy vector według 2 elementu krotek
 +
 +  std::​cout<<​v[0].get<​0>​()<<​v[1].get<​0>​()<<​v[2].get<​0>​()<<​std::​endl; ​ //OK. Wynik tej linii to 213
 +}
 +</​code>​
 + --- //​[[R.Zegadlo@stud.elka.pw.edu.pl|Radosław Zegadło]] 2008/04/13 11:19//
tuple.1207001898.txt.gz · ostatnio zmienione: 2008/04/01 00:18 przez zegadlor