Search
#ifndef ODMENA_HPP_INCLUDED #define ODMENA_HPP_INCLUDED ... #endif
// odmena.cpp Odmena odmenaPro(const Osoba& zaslouzilec) { if (zaslouzilec.povolani == Povolani::cukrar) return Odmena::chlebicky; return Odmena::cokolada; }
// odmena.hpp struct Osoba; enum class Odmena { chlebicky, cokolada }; Odmena odmenaPro(const Osoba& zaslouzilec);
inline
// util.hpp inline int maximum(int a, int b) { return (a > b) ? a : b; }
// osoba.hpp struct Osoba { int kolikTiJe() { if (pohl == Pohlavi::zena) return (4 * vek) / 5; else return vek; } ... };
V dnešním cvičení si hlavně budeme procvičovat psaní šablon. O tom, co šablony jsou a jak fungují, se můžete dozvědět v přednáškové prezentaci nebo na této stránce. Začneme u našeho dobrého známého – vektoru. Pro účely tohoto cvičení je redukovaný a některé metody, které jsme již jednou implementovali v něm nejsou.
array.cpp
copy_array
print_array
resize_array
Nezapomeňte, že šablony musí být umístěny v hlavičkovém souboru, jinak zpravidla dojde k chybě. Přesuňte tedy všechny funkce do souboru array.hpp.
array.hpp
Řešení
Nyní máme k dispozici všechny nástroje k tomu, abychom mohli konečně vytvořit šablonu třídy vector, která přijme libovolný typ.
vector
Chtěli bychom, aby fungoval následující kód:
#include "vector.hpp" #include <string> #include <iostream> #include <algorithm> int main() { vector<double> v; v.push_back(4.56); v.push_back(7.89); v.push_back(1.23); std::sort(v.begin(), v.end()); std::cout << v << '\n'; vector<std::string> u; u.push_back("def"); u.push_back("ghi"); u.push_back("abc"); std::sort(u.begin(), u.end()); std::cout << u << '\n'; }
Nyní máme (redukovaný) šablonový vektor, ale rádi bychom přidali ještě jednu možnost použití, kdy se do vektoru najednou přidá více prvků z jiné kolekce nebo range. Zkrátka bychom chtěli, aby tento kód též fungoval:
#include "vector.hpp" #include <iostream> #include <algorithm> #include <vector> int main() { std::vector<double> vec {1.21, 3.42, 5.123, 4.232, 9.9}; vector<double> v; v.push_back(4.56); v.push_back(7.89); v.push_back(1.23); v.push_back(begin(vec), end(vec)); // Přidá nakonec všechny prvky z vec // v.push_back(std::istream_iterator<double>(std::cin), std::istream_iterator<double>()); -- takto se dají načítat čísla přímo ze stdin std::sort(v.begin(), v.end()); std::cout << v << '\n'; }
template <typename T> class vector { public: ... template <typename InputIterator> void push_back(InputIterator from, InputIterator to) { while (from != to) { push_back(*from); ++from; } }
Náš vektor nyní umí přidat více prvků najednou, ale implementace šablonové metody vector::push_back(InputIterator from, InputIterator to) je velmi primitivní a šla by zlepšit. Například bychom mohli zaručit, že dojde maximálně k jedné alokaci během jednoho volání range push_back, pokud si můžeme předem spočítat kolik nových prvků musíme vložit1).
vector::push_back(InputIterator from, InputIterator to)
push_back
Protože to ale nejde udělat se všemi iterátory, musíme použit metaprogramování, aby se během kompilace zavolala správná metoda.
private
Vyzkoušíme si úpravu funkcionality algoritmu std::sort. Jako třetí parametr tato šablonová funkce očekává komparátor; komparátor má za úkol pro dané dva prvky rozhodnout, zda první je menší než druhý. Predikát může mít několik podob:
std::sort
std::greater
<functional>
Jak docílí std::sort toho, aby mohl příjímat tak široký výběr komparátorů? Ukážeme si, jak to udělat u vlastních funkcí.
is_sorted
vector<double>
Container
Iterator
Comparator
lazy_sort