C++ 11: C++ 11: C++11: jednolita inicjalizacja. C++11: jednolita inicjalizacja. C++11: jednolita inicjalizacja. C++11: initializer_list

Podobne dokumenty
C++11. C++ 11 wybrane elementy. C++11: referencje do rvalue C++ 11: C++11: referencje do rvalue. C++11: referencje do rvalue. Referencje do rvalue

C++11. C++ 11 wybrane elementy. C++11: referencje do rvalue C++ 11: C++11: referencje do rvalue. C++11: referencje do rvalue. Referencje do rvalue

C++11: szablony zewnętrzne C++ 11: C++11: szablony zewnętrzne. C++11: szablony zewnętrzne. C++11: szablony zewnętrzne C++ 11: Szablony zewnętrzne

C++11: metody usunięte i jawnie domyślne C++ 11: Metody usunięte i jawnie domyślne

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

EGZAMIN 2 (14 WRZEŚNIA 2015) JĘZYK C++

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

PARADYGMATY PROGRAMOWANIA Wykład 4

Zaawansowane programowanie w C++ (PCP)

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Programowanie obiektowe w C++ Wykład 12

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Programowanie obiektowe - Przykładowe zadania egzaminacyjne (2005/2006)

EGZAMIN PROGRAMOWANIE II (10 czerwca 2010) pytania i odpowiedzi

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 13 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 30

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Programowanie w C++ Wykład 6. Katarzyna Grzelak. 1 kwietnia K.Grzelak (Wykład 6) Programowanie w C++ 1 / 43

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Wprowadzenie do szablonów szablony funkcji

Wprowadzenie do szablonów szablony funkcji

Programowanie w C++ Wykład 7. Katarzyna Grzelak. 23 kwietnia K.Grzelak (Wykład 7) Programowanie w C++ 1 / 40

Szablony funkcji i szablony klas

Programowanie i struktury danych

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

Szablony klas, zastosowanie szablonów w programach

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

PARADYGMATY PROGRAMOWANIA Wykład 2

Operator przypisania. Jest czym innym niż konstruktor kopiujący!

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

6 Niektóre nowe cechy standardu C++11

Języki i techniki programowania Ćwiczenia 2

Szablony. Szablony funkcji

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy KONSTRUKTORY

PARADYGMATY PROGRAMOWANIA Wykład 3

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Dziedziczenie jednobazowe, poliformizm

Część 4 życie programu

Paradygmaty programowania

Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

Projektowanie klas c.d. Projektowanie klas przykład

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Functionalization. Funkcje w C. Marcin Makowski. 30 listopada Zak lad Chemii Teoretycznej UJ

Programowanie obiektowe Wykład 6. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14

TEMAT : KLASY DZIEDZICZENIE

Zaawansowane programowanie w C++ (PCP)

Wykład 8: klasy cz. 4

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Programowanie, część I

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie C++ - DZIEDZICZENIE.

Szablony funkcji i klas (templates)

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Zaawansowane programowanie w języku C++ Funkcje uogólnione - wzorce

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 15 kwietnia K.Grzelak (Wykład 8) Programowanie w C++ 1 / 33

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

C++ Przeładowanie operatorów i wzorce w klasach

Typy metod: konstruktory, destruktory, selektory, zapytania, iteratory.

Programowanie Obiektowe i C++

Obsługa wyjątków. Język C++ WW12

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Przeciążenie operatorów

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Podstawy programowania skrót z wykładów:

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Język C++ Programowanie obiektowe

C++ - szablony kontenerów. Kontenery i szablony kontenerów. C++ - szablony kontenerów. C++ - szablony kontenerów. C++ - szablony kontenerów

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

Standard C++0x (C++1x?) Marcin Świderski

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy PRAWA PRZYJACIÓŁ KLASY. Dostęp z zewnątrz: Dostęp z wewnątrz:

JAVA W SUPER EXPRESOWEJ PIGUŁCE

STL: Lekcja 1&2. Filozofia STL

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

Metaprogramowanie. C++ - szablony. Metaprogramowanie. Metaprogramowanie. Metaprogramowanie. Metaprogramowanie. Metaprogramowanie

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 7 maja K.Grzelak (Wykład 8) Programowanie w C++ 1 / 31

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Programowanie w języku C++

Programowanie 2. Język C++. Wykład 3.

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

Programowanie w C++ Wykład 13. Katarzyna Grzelak. 4 czerwca K.Grzelak (Wykład 13) Programowanie w C++ 1 / 26

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Zadania z podstaw programowania obiektowego

Do czego służą klasy?

Podstawy Programowania Obiektowego

Programowanie obiektowe, wykład nr 6. Klasy i obiekty

Programowanie Obiektowo Zorientowane w języku C++ Klasy, pola, metody

Programowanie obiektowe w języku C++ dr inż. Jarosław Forenc

Transkrypt:

C++11: jednolita inicjalizacja Jednolita inicjalizacja za pomocą nawiasów klamrowych: Możliwa do zastosowania do dowolnej klasy, struktury czy unii, o ile istnieje (zdefiniowany jawnie lub implicite) konstruktor domyślny: Jednolita inicjalizacja class class_a int main() class_a() // konstruktor domyślny class_a c1; class_a(string str) : class_a c1_1; m_string str class_a c2 "ww" ; class_a(string str, double dbl) : class_a c2_1("xx"); m_string str, class_a c3 "yy", 4.4 ; m_double dbl class_a c3_1("zz", 5.5); double m_double; Kolejność argumentów jak w string m_string; konstruktorze, ponieważ ta ; inicjalizacja de facto wywołuje konstruktor 16 C++11: jednolita inicjalizacja Jednolita inicjalizacja za pomocą nawiasów klamrowych: Jeżeli nie zdefiniowano żadnego konstruktora, domyślny porządek argumentów taki jak pól w deklaracji klasy/struktury/unii: class class_d float m_float; string m_string; wchar_t m_char; ; int main() class_d d1; class_d d1 4.5 ; class_d d2 4.5, "string" ; class_d d3 4.5, "string", 'c' ; class_d d4 "string", 'c' ; // błąd class_d d5("string", 'c', 2.0 ; // błąd C++11: jednolita inicjalizacja Jednolita inicjalizacja za pomocą nawiasów klamrowych: Można jej używać w dowolnym miejscu kodu: class_d* cf = new class_d4.5; kr->add_d( 4.5 ); return 4.5 ; 17 18 C++11: initializer_list Lista obiektów do inicjalizacji: Klasa reprezentuje listę obiektów jednego, określonego typu, które mogą być używane w konstruktorze i innych inicjalizujących kontekstach Klasa initializer_list #include <initializer_list>.. initializer_list<int> ilist1 5, 6, 7 ; initializer_list<int> ilist2( ilist1 ); if (ilist1.begin() == ilist2.begin()) cout << "tak!" << endl; // spodziewamy się "tak!" Standardowe klasy kontenerów z STL, a także np. string mają zdefiniowane konstruktory przyjmujące jako argument listę obiektów. 20 1

C++11: initializer_list C++11: initializer_list Lista obiektów do inicjalizacji: Można używać list w konstruktorach własnych klas: class C1 list<int> L; C1(const std::initializer_list<int>& v) : L(v.begin(), v.end()) ; int main() C1 c 3, 5, 7, 11 ;.. // inicjalizujemy listą wartości Lista obiektów do inicjalizacji: Można używać list do inicjalizacji klas kontenerów wyrażeniami z nawiasami klamrowymi vector<int> v1 9, 10, 11 ; map<int, string> m1 1, "a", 2, "b" ; string s 'a', 'b', 'c' ; 21 22 C++11: static_assert Asercja statyczna: Testuje zadane wyrażenie na etapie kompilacji static_assert Składnia: static_assert( constant-expression, string-literal ); Jeżeli constant-expression zwraca false, wypisywany jest komunikat string-literal, a kompilacja kończy się niepowodzeniem, 24 C++11: static_assert C++11: static_assert Asercja statyczna: Przykłady użycia Jeżeli nieprawda, że rozmiar =4, czyli, że architektura nie jest 32- bitowa, tzn. że musi być 64- bitowa,a tej nie wspieramy.. Asercja statyczna: Przykłady użycia static_assert(sizeof(void *) == 4, "64-bit code generation is not supported."); Jeżeli nieprawda, że wersja > 2, tzn. że musi być 2 lub mniej, a tej już nie wspieramy.. class Foo static const int bar = 3; // prowokujemy błąd.. ; static_assert(foo::bar > 4, "Foo::bar is too small :("); static_assert(somelibrary::version > 2, "Old versions of SomeLibrary are missing the foo functionality. Cannot proceed!"); int main() return Foo::bar; 25 26 2

C++11: static_assert Asercja statyczna: Przykłady użycia template < class T, int Size > class Vector static_assert(size > 3, "Vector size is too small!"); T m_values[size]; ; int _tmain(int argc, _TCHAR* argv[]) Vector< int, 4 > four; // prawda, że: Size>3 Vector< short, 2 > two; // nieprawda, że: Size>3 - błąd return 0; Domyślne wartości parametrów szablonu dla szablonów funkcji 27 C++11: domyślne argumenty szablonu C++11: domyślne argumenty szablonu Domyślne wartości parametrów szablonu dla szablonów funkcji: W C++98 w szablonach klas dozwolone były domyślne argumenty szablonu. W szablonach funkcji nie. Zaczynając od VS2013 wolno nam: template <typename T = int> void Foo(T t = 0) Foo(12L); // Foo<long> Foo(12.1); // Foo<double> Foo('A'); // Foo<char> Foo(); // Foo<int> (!) Domyślne wartości parametrów szablonu dla szablonów funkcji: template <typename T> class Manager void Process(T t) ; template <typename T> class AltManager void Process(T t) ; template <typename T, typename M=Manager<T>> void Manage(T t) M m; m.process(t); Manage(25); // Manage<int, Manager<int>> Manage<int, AltManager<int>>(25); // Manage<int, AltManager<int>> 29 30 C++11: domyślne argumenty szablonu Domyślne wartości parametrów szablonu dla szablonów funkcji: Trzeba jednak uważać na niejednoznaczności: template <typename T = int> void Foo(T t = 0) template <typename B, typename T = int> void Foo(B b = 0, T t = 0) Foo(12L); Foo(12.1); Foo('A'); Foo(); // nie skompiluje się // nie skompiluje się // nie skompiluje się // Foo<int> Metody usunięte i jawnie domyślne 31 3

W C++11 kompilator generuje automatycznie dla przykładowej klasy Klasa: Konstruktor domyślny: Klasa() Konstruktor kopiujący: Klasa(const Klasa& k) Operator przypisania: operator=(const Klasa& k) Destruktor: ~Klasa() Konstruktor przenoszący: Klasa(const Klasa&& k) Operator przypisania przenoszący: operator=(const Klasa&& k) Reguły tworzenia: 1. Jeżeli choć jeden konstruktor został utworzony jawnie, to żadne inne domyślne nie są tworzone 2. Jeżeli wirtualny destruktor został utworzony jawnie, to domyślny destruktor nie jest tworzony 3. Jeżeli konstruktor przenoszący lub operator przypisania przenoszący został utworzony jawnie, to nie są tworzone domyślnie konstruktor domyślny ani operator przypisania domyślny 4. Jeżeli jawnie stworzone zostały: konstruktor kopiujący lub przenoszący, operator przypisania zwykły lub przenoszący, lub destruktor, to nie są tworzone domyślnie konstruktor przenoszący ani operator przypisania przenoszący 33 34 Reguły tworzenia: Te reguły rzutują na obecność składowych klas w przypadku dziedziczenia. Np. jeżeli klasa bazowa nie ma własnego konstruktora domyślnego, który mógłby zostać wywołany w klasie pochodnej, to w klasie pochodnej kompilator nie wygeneruje jej własnego konstruktora domyślnego. Dotychczas, aby jawnie zarządzać tworzeniem lub zakazem tworzenia konstruktorów stosowana była deklaracja w sekcji private: private: CMySingleton() ~CMySingleton() CMySingleton(const CMySingleton&); // Prevent copy-construction CMySingleton& operator=(const CMySingleton&); // Prevent assignment Wady dotychczasowego rozwiązania: 1. Aby ukryć konstruktor kopiujący, trzeba go zadeklarować prywatnie, a skoro jest trzeba też zadeklarować domyślny, choćby nic nie robił, bo inaczej sam się nie utworzy. 2. Nawet jeżeli domyślny nic nie robi, to jest zadeklarowany, a w związku z tym daje większy koszt obliczeniowy wywołania, niż ten utworzony automatycznie przez kompilator. 3. Konstruktor kopiujący i operator przypisania są zadeklarowane prywatne, ale w metodach klasy friend oraz w metodach tej klasy można próbować je wywołać wygenerują błąd linkera (nie mają kodu). 4. Cała konstrukcja klasy dla kogoś, kto nie uważał na wykładach z PO i ZPO, jest niejasna i nieoczywista. 35 36 Składnia w C++98: struct niekopiowalny niekopiowalny() ; private: niekopiowalny(const niekopiowalny&); niekopiowalny& operator=(const niekopiowalny&); ; Składnia w C++11: struct niekopiowalny niekopiowalny() =default; niekopiowalny(const niekopiowalny&) =delete; niekopiowalny& operator=(const niekopiowalny&) =delete; ; Składnia w C++11 korzyści: 1. Generowanie konstruktora domyślnego nadal jest wstrzymane z racji deklaracji konstruktora kopiującego, ale.. można to zmienić korzystając z deklaracji =defaut. 2. Konstruktor kopiujący i operator kopiowania są publiczne, ale usunięte, więc przy próbie ich wywołania lub definiowania pojawi się błąd kompilacji. 3. Intencja autora kodu staje się czytelniejsza, nawet ktoś, kto nie uczęszczał na PO i ZPO, ma szansę się domyślić, co wolno a czego nie wolno używać. 37 38 4

Określanie =default poza deklaracją klasy: Blokowanie niechcianych wywołań: struct widget widget()=default; inline widget& operator=(const widget&); ; inline widget& widget::operator=(const widget&) =default; Konstruktor lub operator można wskazać jako default poza deklaracją klasy tylko pod warunkiem, że został zadeklarowany jako inline. Wskazówka: ze względu na wyższą efektywność, tam gdzie to możliwe, należy zamieniać puste ciała konstruktorów i operatorów na polecenia =default 39 Jeżeli nie chcemy, aby obiekty danego typu były tworzone dynamicznie: struct widget void* operator new(std::size_t) =delete; ; Jeżeli nie chcemy określonych konwersji argumentów w wywołaniach metod lub funkcji: void call_with_true_double_only(float) =delete; void call_with_true_double_only(double param) return; Podanie argumentu typu int wywoła jego konwersję do double. 40 Blokowanie niechcianych wywołań: Jeżeli nie chcemy żadnych konwersji argumentów w wywołaniach metod lub funkcji i chcemy aby argumenty jednego i tylko jednego typu były akceptowane: template < typename T > void call_with_true_double_only(t) =delete; void call_with_true_double_only(double param) return; Pętla for oparta na zakresie 41 C++11: pętla for oparta na zakresie Nowa składnia pętli for for ( deklaracja : wyrażenie ) instrukcje wyrażenie tablica, obiekt implementujący semantykę kontenera (zwraca obiekt w stylu iteratora za pomocą metod begin i end) deklaracja zmiennej - typu takiego jak elementy w tablicy lub kontenerze instrukcje wykonywane tyle razy, ile elementów przechowuje tablica lub kontener Przykład: vector<int> vec; vec.push_back( 10 ); vec.push_back( 20 ); C++11: pętla for oparta na zakresie Przykłady Modyfikowanie zawartości kontenera: vector<int> vec; vec.push_back( 1 ); vec.push_back( 2 ); for (int& i : vec ) i++; // inkrementuje wartości z wektora for (int i : vec ) cout << i; UKSW, WMP. SNS, Warszawa 43 44 5

C++11: pętla for oparta na zakresie Obiekty posiadające zakres to: wszelkie kontenery z biblioteki STL, ponieważ: 1. posiadają iteratory, które wspierają metody operator*, operator!= i operator++ (zadeklarowane jako metody własne albo jako funkcje globalne), 2. posiadają metody begin i end (zadeklarowane jako metody własne albo jako funkcje globalne), zwracające iteratory na początek i koniec kontenera. wszelkie inne obiekty zaimplementowane samemu o funkcjonalności kontenerów STL (obowiązkowa w/w funkcjonalność). Dedukcja typów danych 45 Mechanizmy dedukcji typów danych Pochodzący C++98: 1. Szablony i ich parametry Wprowadzone w C++11: 1. auto 2. decltype Pozwalają uniknąć ciągłego wypisywania typów, które są oczywiste bądź powtarzają się. Zmiana typu zmiennej w jednym miejscu kodu propaguje się na cały kod (kompilator sam dedukuje nowy typ danych uwaga: może nas zaskoczyć). 47 Zasady dedukcji dla auto Podobne do zasad dedukcji dla parametrów szablonu z C++98 Deklarując auto jako typ zmiennej auto x = 10; auto odgrywa rolę taką, jak parametr T w szablonie: template <typename T> void fun(t x) ; fun(10); Stąd: const char name[] = "ABC"; // name: const char[13] auto arr1 = name; // arr1: const char* void Fun(int, double); // Fun: void(int, double) auto func1 = Fun; // func1: void (*)(int, double) 48 Pożytek z auto Mamy szablon funkcji, która na pewnym zakresie elementów kontenera identyfikowanym przez parę iteratorów, wykonuje czynności ważne i potrzebne : template<typename It> // wykonuje czynności ważne i potrzebne void czwip(it b, It e) // na rzecz elementów od 'b' do 'e' for (; b!= e; ++b) typename std::iterator_traits<it>::value_type currvalue = *b; Odwołujemy się pracowicie do cech charakterystycznych iteratora, żeby pozyskać typ danych wskazywanych przez te iteratory. Pożytek z auto Mamy szablon funkcji, która na pewnym zakresie elementów kontenera identyfikowanym przez parę iteratorów, wykonuje czynności ważne i potrzebne : template<typename It> // wykonuje czynności ważne i potrzebne void czwip(it b, It e) // na rzecz elementów od 'b' do 'e' for (; b!= e; ++b) auto currvalue = *b; Wersja dla mniej pracowitych. 49 50 6

Pożytek z auto Jeszcze jeden przykład dla mniej pracowitych : map<string, string> address_book; for ( auto address_entry : address_book ) cout << address_entry.first << " < " << address_entry.second << ">" << endl; Pożytek z auto Kiedy bezpieczniej jest pisać auto przykład: pozyskanie rozmiaru kontenera: std::vector<int> v; unsigned sz = v.size(); Co prawda typ zwracany przez.size() to: vector<int>::size_type ale wszyscy wiedzą, że to typ całkowity bez znaku, więc spotyka się unsigned. Nie wszyscy jednak wiedzą, że choć w Win32 zmienne tych dwóch typów zajmują te samą liczbę bajtów, to już w Win64 nie (unsigned zajmuje mniej).. Rekompilacja kodu na Win64 powiedzie się, ale dla dostatecznie dużych zbiorów danych działanie może przestać być poprawne. Dlatego prościej i bezpieczniej pisać: auto sz = v.size(); 51 52 Niespodzianki z auto Przykład: mamy funkcję, która dla pewnej klasy widgetów zwraca wektor opisujący ich cechy, tj. co potrafią, a czego nie: std::vector<bool> cechy(const Widget& w); Kod programu: Widget w; bool cecha5 = cechy(w)[5]; // czy posiada cechę nr 5.. A gdyby tak napisać: auto cecha5 = cechy(w)[5]; // czy posiada cechę nr 5 Niespodzianki z auto Dla: auto cecha5 = cechy(w)[5]; Typ zmiennej cecha5 to vector<bool>::reference (klasa zagnieżdżona w vector<bool>). Powód jest natury technicznej: klasa vector<bool> została tak zaprojektowana, aby przechowywać wartości w postaci spakowanej jeden bit na każdy element (a w C++ nie ma referencji do pojedynczych bitów). Stąd operator[] dla vector<bool> zwraca obiekt, który działa tak jak bool& Oczywiście, wśród jego wielu funkcjonalności, istnieje też możliwość konwersji tego obiektu do bool. Powinno działać tak samo. 53 54 Niespodzianki z auto Dla: auto cecha5 = cechy(w)[5]; Typ zmiennej cecha5 to vector<bool>::reference (klasa zagnieżdżona w vector<bool>). Teraz zmienna cecha5 jest kopią obiektu przechowującego referencję do właściwej informacji bitu nr 5. Niestety, funkcja cechy zwraca referencję do obiektu, który za chwilę zniknie (funkcja cechy zwraca kontener obiekt tymczasowy, więc jego elementy też są tymczasowe..). Dlatego cecha5 będzie przechowywać referencję do obiektu, który nie istnieje. Niespodzianki z auto Klasa: vector<bool>::reference to tzw. klasa proxy (proxy class). Takich klas jest wiele. Przestroga: należy unikać sytuacji w kodzie, gdzie: auto pewnazmienna = wyrażenie typu klasa proxy ; No tak, tylko że one zostały tak napisane, żeby być jak najmniej widoczne (w założeniu: mają być całkiem niewidoczne). Aby się nie dać oszukać, należy: sprawdzać nagłówki funkcji i metod (np. w źródłach bibliotek), albo.. auto cecha5 = static_cast<bool>(cechy(w)[5]); 55 56 7

Dedukcja typu przez decltype zwraca typ zmiennej lub wyrażenia podanego w argumencie: const int i = 0; bool f(const Widget& w); // decltype(i): const int // decltype(w): const Widget& // decltype(f): bool(const Widget&) struct Point int x, y; // decltype(point::x): int ; // decltype(point::y): int Widget w; if (f(w)) // decltype(w): Widget // decltype(f(w)): bool Dedukcja typu przez decltype Przydaje się szczególnie kiedy szablon funkcji ma zwrócić typ danych zależny od typu parametru (ale nie będący typem parametru) Przykład: funkcja zwracająca element z kontenera po uprzedniej autoryzacji dostępu do danych dla bieżącego użytkownika: template<typename Container, typename Index> (?) authandaccess(container& c, Index i) Funkcja powinna zwracać typ taki, jak ma c[i] Jak go pozyskać? 57 58 Dedukcja typu przez decltype Dygresja: W C++11 wprowadzono możliwość podania typu zwracanego przez funkcję w miejscu tuż za jej nagłówkiem (tzw. trailing return type); bardzo przydatne, kiedy typ zwracanych danych ma skomplikowany zapis, np. : auto fpif(int) -> int(*)(int) Koniec dygresji. Drugie zastosowanie: kiedy zwracany typ zależy argumentów wywołania (trt): template<typename Container, typename Index> auto authandaccess(container& c, Index i) -> decltype(c[i]) authenticateuser(); // autoryzacja dostępu return c[i]; // dostęp do danych 59 8