Szablony funkcji
Transkrypt
Szablony funkcji
Zaawansowane programowanie w C++ (PCP) Wykład 6 - szablony. dr inż. Robert Nowak - p. 1/15 Kolekcje i algorytmy » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu Pojecia ˛ niezależne od typu: kolekcje (np. listy) algorytmy (np. znajdowania najwiekszego ˛ elementu) » Szablony - właściwości » Przykład: std::pair » Szablony funkcji Mechanizmy eliminujace ˛ redundancje˛ kodu. » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki „reczna” ˛ modyfikacja kodu wspólna klasa bazowa wykorzystanie szablonów - p. 2/15 „Reczna” ˛ modyfikacja kodu » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa typedef int Element;//element przykładowego kontenera » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki class WektorInt { public: explicit WektorInt(int size = 10); //konstruktor kopiujacy, ˛ operator przypisania, destruktor const Element& get(int idx) const;//Zwraca element o danym Element& get(int idx);//Zwraca element o danym indeksie //... private: ˛ elementy wektora Element* tab_;//Tablica przechowujaca int size_;//Liczba elementów int capacity_;//Wielkość tablicy }; konieczność recznej ˛ zmiany kodu (błedy!) ˛ utrudnione wprowadzanie modyfikacji (wiele kopii kodu) - p. 3/15 Klasa bazowa » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki #include ¨Object.h¨ class WektorObj { public: explicit WektorInt(int size = 10); //konstruktor kopiujacy, ˛ operator przypisania, destruktor const Object& get(int idx) const;//Zwraca element o danym Object& get(int idx);//Zwraca element o danym indeksie //... private: Object** tab_;//Tablica przechowujaca ˛ elementy wektora //... }; Wady: narzuty pamieciowe ˛ i czasowe problem typów wbudowanych - p. 4/15 Zastosowanie szablonów » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki tempate<class T> class Wektor { public: explicit Wektor(int size = 10); //konstruktor kopiujacy, ˛ operator przypisania, destruktor const T& get(int idx) const;//Zwraca element o danym indek T& get(int idx);//Zwraca element o danym indeksie void add(const T& val);//Dodaje element na koniec kolekcji /* Dalsza cz˛ eść interfejsu klasy */ private: T* tab_;//Tablica przechowujaca ˛ elementy wektora int size_;//Liczba elementów int capacity_;//Wielkość tablicy }; Wektor<int> v;//Kolekcja liczb całkowitych v.add(3); v.add(4);//Operacje na kolekcji Wektor<Data> vd;//Kolekcja obiektów klasy Data Wektor<Figura*> vf;//Kolekcja wskaźników do klasy - p. 5/15 Deklaracja szablonu klasy » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki Deklaracja szablonu: deklaracja-wzorca: template < lista-parametrów-wzorca > deklaracja lista-parametrów-wzorca: parametr-wzorca [,lista-parametrów-wzorca] parametr-wzorca: class identyfikator [= id-typu ] typename identyfikator [= id-typu ] Przykłady: template<class T> class Array { /* oparty o jeden typ */ }; template<typename T, typename U> class Graf{ /* zależny od dwu typów */ }; template<typename T, typename U = int> class BinTree{ /* Domyślny parametr szablonu */ }; - p. 6/15 generowanie typu » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu nazwa-szablonu < typ [,typ] > » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy Przykłady: » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas Array<int> a; std::vector<double> vd; Graf<std::string, std::string> gr; vector<vector<int> > vv; » Zasady tworzenia szablonów » Podział kodu wzorca na pliki Niejednoznaczności: zbyt bliskie położenie kończacych ˛ >, np. vector<vector<int>> v; znak >> jest operatorem przesuniecia ˛ prawidłowe vector<vector<int> > v; (dodatkowa spacja) - p. 7/15 Szablony - właściwości » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu Szablony sa˛ mechanizmem czasu kompilacji pozwalaja˛ współdzielić kod źródłowy brak narzutów czasowych w czasie wykonania » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki Organizacja plików źródłowych definicja (a nie tylko deklaracja) szablonu musi być widoczna w miejscu użycia organizacja plików źródłowych Kod nie jest kompilowany, jeżeli nie został użyty - p. 8/15 Przykład: std::pair » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu Definicja znajduje sie˛ w <utility> » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji template<class _T1, class _T2> struct pair { typedef _T1 first_type; typedef _T2 second_type; » Problem typu » Szablony kontra hierarchia klas _T1 first;//Pierwsza składowa _T2 second;//Druga składowa » Zasady tworzenia szablonów » Podział kodu wzorca na pliki pair() : first(), second() { } pair(const _T1& __a, const _T2& __b) : first(__a), second(__b) { } }; Przykłady użycia: std::pair<std::string,bool> a(¨Ala¨,true); a.first = ¨Ola¨; a.second = false; - p. 9/15 Szablony funkcji » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów Wzorce funkcji: pozwalaja˛ implementować algorytmy niezależne od typu » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki template<typename T> void std::swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } template<typename T> void printAll(const vector<T>& v, std::ostream& os) { for(size_t i = 0; i != v.size(); ++i) os << v[i] << ","; os << endl; } - p. 10/15 Argumenty wzorca funkcji » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów Istnieje możliwość wyznaczania argumentów wzorca z argumentów podanych w wywołaniu » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair template<typename T> void printAll(const vector<T>& v, std::ostream& os) { /* ... * » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki vector<int> w; //dodanie elementów do wektora printAll(w,cout);//printAll<int>(w,cout) template<typename T> T* przydziel() { /* Tworzy obiekt i zwraca wskaźnik */ } int* pi = przydziel<int>();//Niemożliwa automatyczna specjaliz - p. 11/15 Problem typu » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów Typowy problem - jawne wskazanie, że identyfikator jest typem » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki class Foo { public: typedef int Element; /* dalsza cz˛ eść implementacji klasy Foo */ }; template<typename T> void f(const T& t) { //Poniżej bł˛ ednie zakłada, że T::Element to nazwa składowej T::Element e = 0; //... //Poniżej jawnie wskazano, że T::Element to nazwa typu typename T::Element e = 0; //... }; - p. 12/15 Szablony kontra hierarchia klas » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas Używaj szablonów gdy: ważne sa˛ typy wbudowane nie można utworzyć wspólnej klasy podstawowej bardzo ważna jest efektywność akceptowalna jest powtórna kompilacja przy dodawaniu nowego typu » Zasady tworzenia szablonów » Podział kodu wzorca na pliki W przeciwnym wypadku używaj hierarchii klas. - p. 13/15 Zasady tworzenia szablonów » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair 1. 2. 3. 4. zaimplementować typ konkretny przetestować go przekształcić go w szablon wygenerować i przetestować kilka różnych typów » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas » Zasady tworzenia szablonów » Podział kodu wzorca na pliki - p. 14/15 Podział kodu wzorca na pliki » Kolekcje i algorytmy » „Reczna” ˛ modyfikacja kodu Plik ¨kontener.h¨ - definicja klasy » Klasa bazowa » Zastosowanie szablonów » Deklaracja szablonu klasy » generowanie typu » Szablony - właściwości » Przykład: std::pair » Szablony funkcji » Argumenty wzorca funkcji » Problem typu » Szablony kontra hierarchia klas #ifndef KONTENER #define KONTENER template<typename T> class Kontener { /* Definicja klasy i metod inline */ }; #include ¨kontener_impl.h¨ » Zasady tworzenia szablonów » Podział kodu wzorca na pliki #endif Plik ¨kontener_impl.h¨ - implementacja metod wzorca //Nie ma zabezpieczeń przed wielokrotnym dołaczaniem ˛ template<typename T> T& Kontener<T>::get(int index) { /* Definicja metody */ } Plik ¨kontener.cpp¨ - kod niezależny od typu T - p. 15/15