Search
Online záznam: YouTube
Vzorové příklady najdete v repozitáři tutorials v adresáři tut05
tutorials
git pull cd tut05
Alternativně lze najít kódy také v archivu: ppc-tut05.zip
Syntaxe šablony je následující
template<parametry šablony> deklarace
template<class T> void swap(T &a, T &b) { T c(a); a = b; b = c; } // pokud je možné datový typ proměnné dovodit, není třeba explicitně specifikovat int a = 10, b = 20; swap (a, b); // explicitní určení datového typu se provede parametrizací šablony (zde postrádá smysl) swap<int> (a, b);
Parametrem šablony je typ T. Klíčové slovo class značí, že parametrem bude datový typ. Datový typ nemusí být definován třídou, může to být i primitivní datový typ. Kromě class lze použít i klíčové slovo typename, v tomto případě ekvivalentně1). Název datového typu T je obvyklý, nicnméně není nijak závazný. V tomto konkrétním případu jsou tedy argumenty funkce swap reference na proměnné, jejichž hodnoty jsou v těle funkce zaměněny.
class
typename
T
swap
Explicitní specifikace datového typu T umožňuje provést implicitní přetypování skutečných parametrů funkce (pokud je možná konverze. V následujícím příkladu si povšimněte, že funkce je kvalifikována do globálního jmenného prostoru (z důvodu zamezení konfliktu jmen) a nutnosti explicitní parametrizace šablony.
template <class T> T max ( T x, T y ) { return x > y ? x : y; } std::cout << ::max<char> (10, 'b') << std::endl; // zobrazeno b std::cout << ::max<int> (10, 'b') << std::endl; // zobrazeno 98 std::cout << ::max (10, 'b') << std::endl; // deduced conflicting types for parameter 'T' ('int' and 'char')
Parametrem šablony nemusí být jen jeden datový typ:
template <class T1, class T2> T1 min (T1 a, T2 b) { return (a <= b)? a : b; }
Pro některé argumenty funkce nemusí dávat smysl, např. v tomto případě nechceme porovnávat ukazatele, ale dereferencované hodnoty. V tom případě je možné vytvořit přetíženou funkci s explicitním uvedením datových typů argumentů.
int min (int *a, int *b) { return (*a <= *b) ? *a : *b; }
Šablony tříd jsou přirozeným rozšířením šablon funkcí. Již jsme se s nimi setkali v případě STL, kde je možné parametrem šablony specifikovat datový typ prvků kontejneru.
Typickým příkladem může být šablona zásobníku, který bude ukládat položky datového typu T.
template <class T> Stack { T* items; public: Stack(int size = 10); void Push(T x); T Pop(); }; Stack<int> a; // zásobník o defaultní velikosti 10 prvků Stack<int> b(5); // zásobník o velikost 5 prvků
Velikost zásobníku byla v předcházejícím kódu řešena pomocí parametru zásobníku. Je ovšem možné pro tento účel použít také druhý parametr šablony
template <class T, int size> Stack { T items[size]; public: void Push (T x); T Pop(); };
Lambda funkce (výraz) zavádí do C++ možnost velmi elegantně nahradit jednoduché funkce. Obvykle se jedná o operace jako je porovnání prvků, provedení určité matematické operace, atp.
Lambda výraz má následující podobu:
[zachytávané proměnné](seznam formálních parametrů) -> návratový typ {tělo lambda výrazu}(skutečné parametry)
Vytvořme lambda výraz, který provede součet dvou čísel:
[](int a,int b)->int{return a+b;}(2,4);
Výsledek lambda výrazu může být dále využit, např. přiřazen do proměnné.
Pro opakované využití lambda výrazu lze vytvořit ukazatel na lambda výraz a opakovaně jej volat. Ukazatel bude datového typu std::function, nebo možné využít pro zjednodušení deklarace klíčové slovo auto.
auto
auto func=[](int a,int b)->int{return a+b;}; std::cout << func(2,3) << std::endl;
Zatímco v předchozích příkladech byly skutečné parametry předány lambda výrazu explicitně, v případě použití lambdy jako náhrady funktoru mohou být předávány implicitně; např. v případě funkce std::sort jsou předávány hodnoty dvou po sobě následujících prvků v tříděné kolekci.
bool compare(int i,int j){ return (i<j); } std::vector<int> a; // seřazení vektoru vzestupně pomocí funkce std::sort (a.begin(), a.end(), compare); // seřazení vektoru sestupně pomocí lambda funkce std::sort (a.begin(), a.end(), [](int a, int b){return a > b;});
Při implicitním předávání skutečných parametrů funkci je možné pro další parametrizaci funkce využít zachytávání proměnných platných v nadřazené funkci (bloku), jejichž seznam je uveden v hranatých závorkách na začátku lambda výrazů. Dají se zachytávat následovně:
[a, &b]
a
b
[&]
[=]
[=, &x, &y]
x
y
[&, x]
[this]
this
Příklad generování hodnot vektoru pomocí parametrizovaného lambda výrazu. Všimněte si, že inkrementace manipuluje proměnnou index, proto je třeba ji předat jako referenci. V případě zachycení proměnné hodnotou je proměnná konstantou, přístup je možné modifikovat pomocí mutable.
index
mutable
std::vector<int> a(10); int index = 0; generate(a.begin(), a.end(), [&index]{return ++index;});
Proměnnou pro parametrizaci je možné definovat v hranatých závorkách. Pokud má být takto definovanou proměnnou manipulováno, je třeba použít mutable
std::vector<int> a(10); generate(a.begin(), a.end(), [&index]() mutable {return ++index;});
Více o lambda výrazech lze najít např. zde.