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



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

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

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

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Jazyk C++ I. Šablony 2

Jazyk C# (seminář 6)

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

Programování v jazyce C a C++

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

Funkční objekty v C++.

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

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

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

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

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

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

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

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

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

Kolekce, cyklus foreach

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

Šablony, kontejnery a iterátory

Vector datový kontejner v C++.

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

Jazyk C++ II. Šablony a implementace

Jazyk C++ I. Šablony

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

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

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

Konstruktory a destruktory

Univerzita Palackého v Olomouci Radek Janoštík (Univerzita Palackého v Olomouci) Základy programování 4 - C# 3.4.

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

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

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Základní datové struktury

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

Struktura programu v době běhu

Ukazatele, dynamická alokace

Statické proměnné a metody. Tomáš Pitner, upravil Marek Šabo

PREPROCESOR POKRAČOVÁNÍ

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

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

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

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

Generické programování

IB111 Úvod do programování skrze Python Přednáška 7

Základy programování (IZP)

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

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

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

Jazyk C++ II. STL knihovna kontejnery část 2

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

Ukazatel (Pointer) jako datový typ - proměnné jsou umístěny v paměti na určitém místě (adrese) a zabírají určitý prostor (počet bytů), který je daný

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

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

4. Rekurze. BI-EP1 Efektivní programování Martin Kačer

Základy programování (IZP)

Šablony, kontejnery a iterátory

Programování v jazyce C a C++

Jazyk C++ I. Šablony 3

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

Standardní algoritmy vyhledávací.

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

Úvod Třídy Rozhraní Pole Konec. Programování v C# Hodnotové datové typy, řídící struktury. Petr Vaněček 1 / 39

Základy programování (IZP)

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

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

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

Abstraktní datové typy: zásobník

Více o konstruktorech a destruktorech

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

Jakub Čermák Microsoft Student Partner

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

IW5 - Programování v.net a C# 4 Pokročilé konstrukce C#

Doporučené postupy. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze

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

Úvod do programovacích jazyků (Java)

Obsah. Úvod 11 Základy programování 11 Objektový přístup 11 Procvičování 11 Zvláštní odstavce 12 Zpětná vazba od čtenářů 12 Errata 13

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

Jazyk C# (seminář 3)

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

- dělají se také pomocí #define - podobné (použitím) funkcím - předpřipravená jsou např. v ctype.h. - jak na vlastní makro:

Vlákna a přístup ke sdílené paměti. B4B36PDV Paralelní a distribuované výpočty

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

Programování v jazyce JavaScript

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

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

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

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

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

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

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

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

Maturitní otázky z předmětu PROGRAMOVÁNÍ

Dědění, polymorfismus

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

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

Funkce pokročilé možnosti. Úvod do programování 2 Tomáš Kühr

Pole a Funkce. Úvod do programování 1 Tomáš Kühr

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

Transkript:

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

Úvod Na co se podíváme? předávání funkcí do funkcí algoritmická knihovna C++ základy funkcionálního programování v C++11 Co potřebujete C++11 kompatibilní kompilátor >= gcc 4.8, clang 3.4, VS CTP 2013 možná budou fungovat i starší na školních pc module add gcc-4.8.2 (odeberte ostatní gcc moduly) Hrátky s funkcemi PV173 29. září 2014 2 / 23

Předávání funkce do funkce Často se hodí různé callbacky porovnávací funkce pro sort funkce jako for_each, accumulate zavolání funkce pro každý vrchol stromu... Hrátky s funkcemi PV173 29. září 2014 3 / 23

Předávání funkce do funkce implementace ukazatele na funkci znáte z C void qsort( void *ptr, size_t count, size_t size, int (*comp)(const void *, const void *) ) {... comp( a, b )... } + funguje v C++98 a bez šablon (a i v C) ± typová signatura callbacku přesně definovaná neumožňuje předat do funkce funktory (objekty implementující operátor ()) nepodporuje všechny typy C++11 lambd lze předat NULL či nullptr místo funkce Hrátky s funkcemi PV173 29. září 2014 4 / 23

Předávání funkce do funkce implementace C++11 function wrapper #include <functional> template< typename T > void mysort( std::vector< T > &vec, std::function< bool(const T&, const T&) > cmp ) {... cmp( a, b )... } + funguje i s lambdami a funktory ± typová signatura callbacku explicitně definovaná, ale konverze možné zbytečný overhead, nelze inlinovat volání předaný objekt může být nevalidní volání vyhodí std::bad_function_call jen C++11 a dále Hrátky s funkcemi PV173 29. září 2014 5 / 23

Předávání funkce do funkce implementace pomocí šablon template< class RandomIt, class Compare > void sort( RandomIt first, RandomIt last, Compare comp ) {... comp( a, b )... } + funguje i s lambdami a funktory + funguje v C++98 + kompilátor může snadno inlinovat callback + nelze jednoduše zavolat s NULL či nullptr (bez explicitní konverze na typ ukazatele na funkci) ± typová signatura callbacku definovaná jen jeho použitím pokud callback nelze zavolat s danými parametry je typová hláška hůře srozumitelná musí být šablona (tedy definovaný v.h) Hrátky s funkcemi PV173 29. září 2014 6 / 23

Předávání funkce do funkce implementace co teda? pokud je možné implementovat jako šablonu používejte poslední možnost šablonová verze se hojně (a výhradně) používá v C++ standardní knihovně pokud nutně musíte nemít šablonu, použijte std::function nepoužívejte ukazatele na funkce, jsou příliš omezující a nemají téměř žádné výhod proti std::function Hrátky s funkcemi PV173 29. září 2014 7 / 23

Algoritmická knihovna v C++ http://en.cppreference.com/w/cpp/algorithm hlavičky <algoritm> a <numeric> řazení, vyhledávání, akumulace v kontejnerech; haldy... mnohé funkce berou funkci: find_if, all_of, sort,... Hrátky s funkcemi PV173 29. září 2014 8 / 23

Příklad: suma pomocí std::for_each Máme std::vector< int >, chceme spočítat sumu pomocí funkce std::for_each: template< class InputIt, class UnaryFunction > UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f ); problém: jak si držet sumu nesmíte použít globální ani statickou proměnnou Hrátky s funkcemi PV173 29. září 2014 9 / 23

Příklad: suma pomocí std::for_each Máme std::vector< int >, chceme spočítat sumu pomocí funkce std::for_each: template< class InputIt, class UnaryFunction > UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f ); problém: jak si držet sumu nesmíte použít globální ani statickou proměnnou nelze udělat s pomocí běžné funkce, vyžaduje volatelný objekt Hrátky s funkcemi PV173 29. září 2014 9 / 23

Příklad: suma pomocí std::for_each C++98 řešení: funktory (volatelné objekty) int dosum( std::vector< int > &vec ) { struct MkSum { MkSum() : sum( 0 ) { } int sum; // uděláme objekt volatelným void operator()( int val ) { sum += val; } }; return std::for_each( vec.begin(), vec.end(), MkSum() ).sum; }... neprakticky dlouhé a nepřehledné Hrátky s funkcemi PV173 29. září 2014 10 / 23

Příklad: suma pomocí std::for_each C++11 řešení: lambda funkce int dosum( std::vector< int > &vec ) { int sum = 0; std::for_each( vec.begin(), vec.end(), [&]( int val ) { sum += val; } ); return sum; } krátké a přehledné [&] na začátku lambda funkce říká, že chceme přistupovat ke všem lokálně přístupným proměnným pomocí reference kompilátor na pozadí vytvoří funktor Hrátky s funkcemi PV173 29. září 2014 11 / 23

Lambda funkce [ <zachycení proměnných> ]( <parametry> ) { <tělo> } <parametry> jsou normální parametry funkce obdobně <tělo> <zachycení proměnných> dále návratová hodnota se v C++11 odvodí jen pokud je tělo tvaru return <výraz>, jinak je void v C++14 funguje odvození stejně jako pro auto funkce (= skoro vždy) lze specifikovat explicitně [ <zachycení proměnných> ]( <parametry> ) -> <návratová hodnota> { <tělo> } Hrátky s funkcemi PV173 29. září 2014 12 / 23

Lambda funkce zachytávání proměnných Sekce <zachycení proměnných> může obsahovat: <proměnná> pro zachycení hodnotou &<proměnná> pro zachycení referencí = pro zachycení všech nespecifikovaných proměnných hodnotou & pro zachycení všech nespecifikovaných proměnných referencí může být prázdná (ale [] musí být) nezachycené proměnné jsou nedefinované a to včetně this pro lambdy vnořené v metodě objektu [&sum,=]( int val ) {... } zachycuje sum referencí a ostatní použité proměnné hodnotou Hrátky s funkcemi PV173 29. září 2014 13 / 23

Lambda funkce zachytávání proměnných pozor zachycení proměnné nemění její životnost proměnné zachycené hodnotou jsou uvnitř lambdy const Kde je chyba? std::function< int( int ) > getadder( int c ) { return [&]( int val ) { return c + val; }; } int main() { auto add5 = getadder( 5 ); std::cout << add5( 1 ) << std::endl; return 0; } Hrátky s funkcemi PV173 29. září 2014 14 / 23

Cvičení I Definujte funkci foreach chovající se jako knihovní for_each (funkce f může měnit hodnoty v kontejneru) template< typename InputIt, /*... */ > void foreach( InputIt fst, InputIt lst, /*... */ f ); Taky aby: a) používala ukazatel na funkci b) používala std::function c) používala šablonovaný callback poznámka: typ hodnot je typename InputIt::value_type Hrátky s funkcemi PV173 29. září 2014 15 / 23

Cvičení II Definujte funkci foreach chovající se jako knihovní for_each (funkce f může měnit hodnoty v kontejneru) template< typename InputIt, /*... */ > void foreach( InputIt fst, InputIt lst, /*... */ f ); Taky aby: a) používala ukazatel na funkci b) používala std::function c) používala šablonovaný callback poznámka: typ hodnot je typename InputIt::value_type Porovnejte jejich chování pro volání: foreach(b,e, [](int &x) { std::cout << x; }); foreach(b,e, [](int x) { std::cout << x; }); foreach(b,e, [&](int &x) { sum +=x; }); Hrátky s funkcemi PV173 29. září 2014 15 / 23

Cvičení III Definujte následující funkce bez použití cyklů a rekurze: // spočítá průměr hodnot v rozsahu [fst, lst) template< typename InputIt > auto average( InputIt fst, InputIt lst ) -> typename InputIt::value_type; // spočítá průměr těch hodnot v rozsahu // [fst, lst), které splňují pred template< typename InputIt, typename UnaryPred > auto average_if( InputIt fst, InputIt lst, UnaryPred pred ) -> typename InputIt::value_type; Bonus: definujte average pomocí average_if. Hrátky s funkcemi PV173 29. září 2014 16 / 23

Typové chyby ukazatel na funkci 1 int callfp ( int (*fp)(int) ) { return fp (5); } 2 int main () { 3 callfp ( []( int x ) { return x + 1; } ); 4 callfp ( []( const int &x ) { return x; } ); 5 callfp ( []( int &x ) { return x + 2; } ); 6 } /* 7 ferr_fp. cpp :4:5: error: no matching function for call to callfp 8 callfp ( []( const int &x ) { return x; } ); 9 ^~~~~~ 10 ferr_fp. cpp :1:5: note: candidate function not viable : no known conversion from < lambda at ferr_fp.cpp :4:13 > to int (*)(int) for 1st argument 11 int callfp ( int (*fp)(int) ) { return fp (5); } 12 ^... totéž pro řádek 5 Hrátky s funkcemi PV173 29. září 2014 17 / 23

Typové chyby std::function 1 # include < functional > 2 void call(std :: function <int(int)> f) { f(5); } 3 int main () { 4 call( []( int x ) { return x + 1; } ); 5 call( []( const int &x ) { return x; } ); 6 call( []( int &x ) { return x + 2; } ); 7 } /* 8 ferr_fw. cpp :6:5: error: no matching function for call to call 9 call( []( int &x ) { return x + 2; } ); 10 ^~~~ 11 ferr_fw. cpp :2:6: note: candidate function not viable : no known conversion from < lambda at ferr_fw.cpp :6:11 > to std :: function <int ( int) > for 1 st argument 12 void call(std :: function <int(int)> f) { f(5); } 13 ^ 14 1 error generated. 15 */ Hrátky s funkcemi PV173 29. září 2014 18 / 23

Typové chyby šablony 1 template< typename F > 2 void call( F f ) { f(5); } 3 int main() { 4 call( []( int x ) { return x + 1; } ); 5 call( []( const int &x ) { return x; } ); 6 call( []( int &x ) { return x + 2; } ); 7 } Hrátky s funkcemi PV173 29. září 2014 19 / 23

Typové chyby šablony ferr_t. cpp :2:20: error: no matching function for call to object of type < lambda at ferr_t.cpp :6:11 > void call( F f ) { f(5); } ^ ferr_t. cpp :6:5: note: in instantiation of function template specialization call <<lambda at ferr_t.cpp :6:11 > > requested here call( []( int &x ) { return x + 2; } ); ^ ferr_t. cpp :6:11: note: candidate function not viable : expects an l- value for 1 st argument call( []( int &x ) { return x + 2; } ); ^ ferr_t. cpp :6:11: note: conversion candidate of type int (*)(int &) 1 error generated. Hrátky s funkcemi PV173 29. září 2014 20 / 23

Typové chyby závěr funkční ukazatel je příliš restriktivní C++11 ve skutečnosti negarantuje, že příklad na std::function se nezkompiluje! může se zkompilovat a volání vyhodit std::bad_function_call C++14 již chybovou hlášku garantuje u šablon se chyba generuje v místě volání callbacku musíme procházet poznámky a zjišťovat co se vlastně stalo Hrátky s funkcemi PV173 29. září 2014 21 / 23

Lambda funkce v C++14 Odvozování návratového typu (pokud není uveden) všechny return výrazy musí mít stejný typ Generické lambda funkce []( auto x, auto y ) { return x < y; } chová se jako kdyby každý auto parametr byl samostatně šablonovaný, tedy jako struct Closure { template< typename T1, typename T2 > auto operator()( T1 x, T1 y ) { return x < y; } }; Překlad: gcc/clang s -std=c++1y (-std=c++14 od clang 3.5). Hrátky s funkcemi PV173 29. září 2014 22 / 23

Domácí úkol Implementujte třídu Vector< T >, která se chová stejně jako std::vector< T > a navíc má dotazovací funkce (accumulate, sum, average, median, foreach, map,... ) inspirované funkcionálním programováním a C# LINQ (které je samo inspirované funkcionálním programováním). Kompletní zadání naleznete na http://cecko.eu/public/pb173/cviceni_03. V ISu je odevzdávárna. Odevzdávejte do 13. 10. 2014 14:00. Hrátky s funkcemi PV173 29. září 2014 23 / 23