PB přednáška (23. listopadu 2015)

Podobné dokumenty
PB161 Programování v jazyce C++ Přednáška 10

PB161 Programování v jazyce C++ Přednáška 10

Jazyk C++ II. Šablony a implementace

Hrátky s funkcemi. PV173 Programování v C++11. Vladimír Štill, Jiří Weiser. Fakulta Informatiky, Masarykova Univerzita. 29.

PB161 Programování v jazyce C++ Přednáška 9

Jazyk C++ I. Šablony

Jazyk C++ I. Šablony 2

Šablonové metaprogramování v C++ Miroslav Virius KSI FJFI ČVUT

PB161 Programování v jazyce C++ Přednáška 7

PB161 Programování v jazyce C++ Přednáška 7

PB161 Programování v jazyce C++ Přednáška 4

Programování se šablonami

Programování v C++ 1, 1. cvičení

PB161 Programování v jazyce C++ Přednáška 11

Funkční objekty v C++.

Vector datový kontejner v C++.

Jazyk C++ I. Šablony 3

Pokročilé programování v jazyce C pro chemiky (C3220) Statické proměnné a metody, šablony v C++

přetížení operátorů (o)

přetížení operátorů (o)

PB161 Programování v jazyce C++ Přednáška 11

Jazyk C++, některá rozšíření oproti C

Zpracoval:

PB161 Programování v jazyce C++ Přednáška 4

PB161 Programování v jazyce C++ Přednáška 3

PB161 Programování v jazyce C++ Přednáška 1

PREPROCESOR POKRAČOVÁNÍ

Jazyk C++ I. Polymorfismus

PB161 Programování v jazyce C++ Přednáška 3

Programování v C++ 1, 14. cvičení

PROGRAMOVÁNÍ V C++ CVIČENÍ

Úvod do programovacích jazyků (Java)

PB161 Programování v jazyce C++ Přednáška 1

PB161 Programování v jazyce C++ Přednáška 9

Dědění, polymorfismus

PB161 Programování v jazyce C++ Přednáška 5

Programování v C++ 1, 5. cvičení

Šablony funkcí a tříd (Templates) Genericita

Cvičení z programování v C++ ZS 2016/2017 Přemysl Čech

Odvozené a strukturované typy dat

Šablony, kontejnery a iterátory

PB161 Programování v jazyce C++ Přednáška 9

PŘETĚŽOVÁNÍ OPERÁTORŮ

PB161 Základy OOP. Tomáš Brukner

map, multimap - Asociativní pole v C++.

PROGRAMOVÁNÍ V C++ URČENO PRO VZDĚLÁVÁNÍ V AKREDITOVANÝCH STUDIJNÍCH PROGRAMECH ROSTISLAV FOJTÍK

8 Třídy, objekty, metody, předávání argumentů metod

Polymorfismus. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 30.března

Jazyk C++ 1. Blok 3 Objektové typy jazyka C++ Třída. Studijní cíl. Doba nutná k nastudování. Průvodce studiem

Jazyk C# (seminář 6)

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

PB161 Programování v jazyce C++ Přednáška 8

IUJCE 07/08 Přednáška č. 1

Ukazatele, dynamická alokace

C++ objektově orientovaná nadstavba programovacího jazyka C

Přetěžování operátorů, dynamika objektů 2

Základy C++ I. Jan Hnilica Počítačové modelování 18

IB111 Programování a algoritmizace. Objektově orientované programování (OOP)

Jakub Čermák Microsoft Student Partner

Výčtový typ strana 67

PB přednáška (12. října 2015)

C++ objektově orientovaná nadstavba programovacího jazyka C

Dynamika objektů. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

Programování v C++ 1, 6. cvičení

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

PB161 Programování v jazyce C++ Přednáška 5

Generické programování

OBJEKTOVÉ PROGRAMOVÁNÍ V C++ V PŘÍKLADECH 8 Proudová knihovna 8.1 Hierarchie proudů Standardně zavedené proudy

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Úvod. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík,2016

Datové typy v Javě. Tomáš Pitner, upravil Marek Šabo

IUJCE Přednáška č. 11. další prvky globální proměnné, řízení viditelnosti proměnných, funkcí

PB přednáška (26. října 2015)

Programování v C++ 2, 4. cvičení

Výrazy, operace, příkazy

Ukazka knihy z internetoveho knihkupectvi

Množina v C++ (set, multiset).

Teoretické minimum z PJV

Šablony, kontejnery a iterátory

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. October 17, 2016

C++ přetěžování funkcí a operátorů. Jan Hnilica Počítačové modelování 19

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

Programování v C++ 3, 3. cvičení

Lekce 6 IMPLEMENTACE OPERAČNÍHO SYSTÉMU LINUX DO VÝUKY INFORMAČNÍCH TECHNOLOGIÍ JAZYK C

Struktury, funkce, reference

Úvod do programovacích jazyků (Java)

Pokročilé programování v jazyce C pro chemiky (C3220) Pokročilá témata jazyka C++

Jazyk C# (seminář 3)

Programování v jazyce C a C++

Jazyk C++ II. Výjimky

Třídy a struktury v C++

Přetěžování operátorů

Preprocesor. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2016

Konec a tak. PB173 Programování v C++11. Vladimír Štill, Jiří Weiser. Fakulta Informatiky, Masarykova Univerzita. 15.

PB161 Programování v jazyce C++ Přednáška 2

Výrazy, operace, příkazy

Programování v C++ 2, 8. cvičení

Objektově orientované programování

GENERICKÉ PROGRAMOVÁNÍ: CÍLE A MOŽNOSTI IMPLEMENTACE

Transkript:

PB161 10. přednáška (23. listopadu 2015) Šablony Motivace snaha o co nejmenší duplikaci kódu co když máme kód, který chceme použít pro různé typy? generická funkce (maximum, minimum, swap, ) kontejnery algoritmy možné řešení (C): makra žádná typová bezpečnost různé druhy problémů (vzpomeňte si na makra v C) kontejnery: škaredé triky s #define a #include možné řešení (C): používání void * používá např. qsort není typově bezpečné objekty v kontejnerech: jen jako ukazatele možné řešení: OOP polymorfismus vyžaduje pozdní vazbu, což může být pomalé vyžaduje, aby všechny myslitelné typy byly součástí jedné hierarchie (např. Object v Javě) není možné použít pro primitivní typy (int, double) řešení v C++: šablony jiný druh polymorfismu generické programování metaprogramování standardní knihovna v C++ z velké části používá šablony Šablony můžeme je chápat jako lepší makra (ovšem výrazně lepší) umožňují psát kód, v němž jsou díry pro typy, které se doplní později (a mohou se doplnit víckrát různě) tzv. instanciace a nemusí jít jen o typy, jak uvidíme později instanciace probíhá při kompilaci narozdíl od generik v Javě šablony mohou využívat funkce i třídy od C++11 i typové aliasy pomocí using (viz dále) (od C++14 i proměnné) Syntax syntax šablonové deklarace: template <seznam parametru> parametr může být jeden nebo více C++11 variadické parametry (viz speciální přednášku) 1

šablonové parametry: druh jmeno (jméno je nepovinné) druh může být typ: typename hodnota: celočíselný typ (int, bool, ), reference, ukazatel, výčtový typ (definovaný pomocí enum) šablona parametr může mít implicitní hodnotu (pomocí =) místo typename je možno použít i slovo class má úplně stejný význam (tj. označuje libovolný typ, ne jen třídy) proto je možná lepší používat spíš typename Příklad: template <typename T, int size = 100, typename U = bool> za deklarací šablony následuje entita, která je danou šablonou parametrizována typicky funkce nebo třída Šablony funkcí cokoli, co bude řečeno o funkcích, platí stejně i pro metody definice šablonové funkce const T & mymax(const T & x, const T & y) { return x < y? y : x; použití šablonové funkce #include <iostream> int a, b; std::cin >> a >> b; // explicitní hodnota šablonového parametru std::cout << mymax<int>(a, b) << std::endl; // překladač může sám dedukovat std::cout << mymax(a, b) << std::endl; // ovšem typy musí sedět přesně unsigned long c = 17; std::cout << mymax(a, c) << std::endl; // CHYBA // tohle je OK: std::cout << mymax<unsigned long>(a,c) << std::endl; šablonové funkce se mohou přetěžovat 2

#include <vector> #include <algorithm> const T & mymax(const T & x, const T & y, const T & z) { return mymax( mymax(x, y), z ); const T & mymax( const std::vector<t> & vec ) { return *max_element(vec.begin(), vec.end()); std::cout << mymax(2.0, 3.14) << std::endl; std::cout << mymax(2.0, 3.14, 42.0) << std::endl; std::vector<unsigned> v{ 10, 40, 20, 70, 30 ; std::cout << mymax(v) << std::endl; funkce může být přetížená šablonovou i nešablonovou verzí nešablonová verze má přednost #include <cstring> const char * mymax(const char * x, const char * y) { return strcmp(x,y) < 0? y : x; // zavolá se šablonová funkce mymax<int> std::cout << mymax(20, 70) << std::endl; // zavolá se nešablonová funkce mymax std::cout << mymax("ahoj", "hello") << std::endl; // co se zavolá teď? std::cout << mymax<const char*>("ahoj", "hello") << std::endl; šablonové funkce se sice mohou i specializovat (viz specializaci u šablonových tříd), ale nedoporučuje se to používat neintuitivní chování při přetěžování viz http://www.gotw.ca/publications/mill17.htm syntax pro automatickou dedukci šablonového typu jen jméno funkce: umožňuje přetížení nešablonovou verzí 3

funkce a prázdný seznam šablonových parametrů <>: neumožňuje přetížení nešablonovou verzí částečná automatická dedukce: vynechání některých parametrů template<typename T, typename U> T convert(const U & value) { T x = static_cast<t>(value); return x; // tohle nebude fungovat, není jak dedukovat oba parametry: std::cout << convert(3.14) << std::endl; // CHYBA // tohle je OK: std::cout << convert<int, double>(3.14) << std::endl; // částečná dedukce: std::cout << convert<int>(3.14) << std::endl; Šablony tříd definice šablonové třídy Příklad: Jednoduchý kontejner #include <iterator> class MyContainer { size_t size; T * array; MyContainer(size_t n) : size(n), array(new T[n]()) { ~MyContainer() { delete array; MyContainer(const MyContainer & other) : size(other.size), array(new T[size]) { std::copy(other.array, other.array + size, array); void swap(mycontainer & other) { using std::swap; swap(size, other.size); swap(array, other.array); MyContainer & operator=(mycontainer other) { swap(other); return *this; 4

; void output() const { std::copy(array, array+size, std::ostream_iterator<t>(std::cout, " ")); použití šablonové třídy MyContainer<double> cont(10); cont.output(); std::cout << std::endl; odbočka k zamyšlení: jaký je rozdíl mezi new int[10] a new int[10]()? u šablonových tříd není žádná automatická dedukce to je důvod pro funkce jako std::make_pair class Foo { //... Foo(const T &); //... ; Foo<T> make_foo(const T & val) { return Foo<T>(val); auto foo = make_foo(1); uvnitř šablonových tříd mohou být šablonové metody class Foo { T value; Foo(const T & val) : value(val) { template <typename U> void print(const U & thing) { std::cout << value << " : " << thing << std::endl; 5

; Foo<double> foo(3.14); foo.print("example"); // 3.14 : example Specializace můžeme chtít speciální implementaci pro konkrétní šablonové parametry jiný způsob zacházení s daty efektivnější implementace funkce můžeme přetěžovat, ale u tříd nemáme jak proto je možné šablony specializovat úplná specializace šablony (pro třídy) uvozená deklarací template <> za názvem třídy konkrétní parametry v < > class X { /*... */ ; template <> class X<int> { /* speciální implementace pro int */ ; kromě tříd se můžou úplně specializovat funkce (spíš nepoužívat) metody šablonových tříd statické atributy šablonových tříd a další (viz http://en.cppreference.com/w/cpp/language/template_ specialization) template <typename T, typename U> class X { void foo() { std::cout << "unspecialised!\n"; ; template <> void X<int,double>::foo() { std::cout << "specialised!\n"; 6

X<int, int> x; X<int, double> y; x.foo(); y.foo(); částečná specializace šablony (jen pro třídy) uvozená deklarací template <nespecializovane parametry> nespecializované parametry je pak možno použít v seznamu parametrů za názvem třídy template <typename T, typename U> class X { /*... */ ; // 1 class X<T, double> { /*... */ ; // 2 class X<T, T> { /*... */ ; // 3 class X<int, T> { /*... */ ; // 4 X<double, char> x1; // použije se verze 1 X<char, double> x2; // použije se verze 2 X<char, char> x3; // použije se verze 3 X<int, char> x4; // použije se verze 4 X<int, int> x5; // CHYBA! není jasné, kterou verzi použít doporučení pro specializace specializace by se navenek neměly chovat jinak než v obecném případě příklad specializace ve standardní knihovně std::vector<bool> trochu kontroverzní Typové aliasy v C++11 šablonové template<typename Element, typename Allocator> class BasicContainer { /*... */ ; template<typename Element> class StandardAllocator { /*... */ ; template<typename Element> 7

using Container = BasicContainer<Element, StandardAllocator<Element>>; Container<double> c; // totéž, co BasicContainer<double, // StandardAllocator<double>> nešablonové fungují jako typedef, jen s jinou syntaxí using VectorInt = std::vector<int>; using Number = int; using Function = void (*) (int, int); class Container { using valuetype1 = T; typedef T valuetype2; ; Použití šablon funkční objekty jak fungují algoritmy ve standardní knihovně? funkci/funkční objekt berou jako šablonový argument template<typename Iterator, typename Function> void modify(iterator from, Iterator to, Function func) { for (auto it = from; it!= to; ++it) { *it = func(*it); Šablony nejen typové parametry šablon mohou být nejen typy, ale i (některé) hodnoty celočíselných typů (včetně bool, char) výčtových typů reference, ukazatele šablony instance parametrů musí být konstantní výrazy (jejich hodnota musí být známa při překladu) Příklad použití ze standardní knihovny: 8

template <typename T, std::size_t N> class array { T _array[n]; //... ; // klasický příklad: faktoriál při překladu template <unsigned N> struct Factorial { const static unsigned value = N * Factorial<N-1>::value; ; template <> struct Factorial<0> { const static unsigned value = 1; ; // hodnota se spočítá při překladu, ne za běhu! return Factorial<5>::value; Šablony jako parametry šablon parametrem šablony může být opět šablona template< typename Value, template <typename> class Container > class X { Container<Value> cont; //... ; // použití X<int, std::vector> x; // x obsahuje atribut cont typu std::vector<int> Instanciace šablona samotná nedeklaruje žádnou funkci nebo třídu ty vznikají až instanciací instanciace (vytvoření konkrétní instance) jakmile se v kódu objeví konkrétní použití šablony prototyp nebo použití funkce použití třídy explicitní instanciace (class Container<int>;) 9

pro instanciaci je třeba, aby kompilátor viděl celou definici šablonové třídy důsledek linker musí vědět o šablonách a musí je umět instanciovat podle potřeby nebo musí být šablonové třídy a funkce v hlavičkovém souboru realita: šablony musí být v hlavičkovém souboru Instance se vytváří jen pro to, co se skutečně použije: template<typename T> class X { T t; void f() { t.f(); void g() { t.g(); ; class A { void f() { ; X<A> x; x.f(); // takhle je to OK // x.g(); // po odkomentování se nezkompiluje Nápověda pro překladač typename class Container { typedef T value_type; using ptr_type = T *; using size_type = unsigned int; size_type size(); //... ; void do_something(container<t> & cont) { // nebude fungovat: Container<T>::size_type size = cont.size(); // je třeba napsat: typename Container<T>::size_type size = cont.size(); 10