Programowanie Obiektowo Zorientowane w jezyku C++...

37
Programowanie Obiektowo Zorientowane w języku C++ Rozszerzenia C++17 Miroslaw Glowacki 1 1 Akademia Górniczo-Hutnicza im. Stanislawa Staszica w Ktrakowie Wydzial Inżynierii Metali i Informatyki Stosowanej Katedra Informatyki Stosowanej i Modelowania Lipiec 2018 Miroslaw Glowacki (AGH, UJK) Programowanie w języku C++ 2018 1 / 29

Transcript of Programowanie Obiektowo Zorientowane w jezyku C++...

Programowanie Obiektowo Zorientowanew języku C++

Rozszerzenia C++17

Mirosław Głowacki 1

1Akademia Górniczo-Hutnicza im. Stanisława Staszica w KtrakowieWydział Inżynierii Metali i Informatyki StosowanejKatedra Informatyki Stosowanej i Modelowania

Lipiec 2018

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 1 / 29

Spis treści

1 Nowe elementy językaWiązanie strukturInstrukcja if z inicjalizatorami zmiennychInstrukcja switch z inicjalizatorami zmiennychStatyczne pola wbudowaneAgregaty i ich inicjalizacjaCopy elisionNowe atrybutyZagnieżdżone przestrzenie nazwWyrażenia lambda w C++17

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 2 / 29

Spis treści

1 Nowe elementy językaWiązanie strukturInstrukcja if z inicjalizatorami zmiennychInstrukcja switch z inicjalizatorami zmiennychStatyczne pola wbudowaneAgregaty i ich inicjalizacjaCopy elisionNowe atrybutyZagnieżdżone przestrzenie nazwWyrażenia lambda w C++17

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 3 / 29

Wiązanie struktur

Deklaracja wiązania struktur przypisuje określone nazwy dopodobiektów lub elementów inicjalizatora.

Podobnie jak referencja, powiązanie takie jest aliasem doistniejącego obiektu.

W przeciwieństwie do referencji, typ powiązania nie musi byćtypem odniesienia.Można wyróżnić trzy przypadki takiego wiązania:

wiązanie tablic,wiązanie typów o charakterze krotek,wiązanie pól klas.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 4 / 29

Wiązanie tablic

Pierwszy z przypadków można zobrazować przykładem:

1 int a[2] = {1,2};2 auto [x,y] = a;3 auto& [xr, yr] = a;

W wierszu 2 kodu tworzona jest tablica dwuelementowa beznazwy, do której zostaje skopiowana tablica a , po czymnastępuje przypisanie zmiennej x elementu tej tablicy o indeksie0 , a zmiennej y elementu o indeksie 1 .

W wierszu 3 następuje przypisanie zmienenym xr i yrelementów o indeksach 0 i 1 tablicy a .

Liczba zmiennych musi być równa licznie elementów tablicy.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 5 / 29

Wiązanie krotek

A oto przykład drugiego z przypadków:

float x{1.35};char y{'Z'};int z{25};std::tuple<float&,char&&,int> tpl(x,std::move(y),z);const auto& [a,b,c] = tpl;

Tym razem a jest nazywą wiązania, która odnosi się doelementu x krotki tpl , który jest typu float&Encja b oznacza wiązanie, które odnosi się do elementu y typuchar&& tejże krotki ,

Natomiast c jest nazywą wiązania, które odnosi się do trzeciegoelementu tpl typu const intLiczba identyfikatorów wiązania musi się równać rozmiarowikrotki.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 6 / 29

Wiązanie pól struktur

Trzeci z przypadków można przedstawić następująco:

1 struct myStr {2 int x1 : 2; volatile double y1 = 4.56; };3 myStr f(){myStr s; return s;}4 const auto [x, y] = f();

Zdefiniowana w wierszu nr 3 funkcja f() zwraca obiekt typumyStr , a instrukcja przedstawiona w wierszu nr 4 powoduje

wiązanie do zmiennych x i y pól x1 i y1 w kolejności wjakiej te pola występuja.

Zmienna x jest l-wartością typu const int .

Zmienna y jest l-wartością typu const volatite double .

Liczba identyfikatorów wiązania musi się równać liczbie pól klasy.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 7 / 29

Instrukcja if z inicjalizatorami zmiennych

Nowa postać instrukcji if , tzw. if z inicjatorem umożliwiautworzenie zmiennej wewnątrz zakresu instrukcji if .Powoduje to, że kod jest bardziej zwarty i nie przenosi zmiennejdo otaczającego zakresu.

1 string sTab[] = {"Ala", "Ela", "Ula"};2 for (auto& str: sTab)3 if(auto& imie = str; imie == "Ela")4 cout << "Ela wystepuje w spisie" << endl;5 cout << imie << endl; // Błąd kompilacji

W nawiasie okrągłym instrukcji if instrukcja warunkowapoprzedzona jest instrukcją inicjalizującą lokalną zmienną imie .Zakresem tej zmiennej jest instrukcja if łącznie z następującąpo niej instrukcją else (tu wiersze nr 3 i 4).W wierszu nr 5 przykładowego kodu encja imie jest jużnieznana, co spowoduje błąd kompilacji.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 8 / 29

Instrukcja if z inicjalizatorami zmiennych

Wyrażenie inicjalizujące może być równocześnie warunkiem jeśliinicjalizowana zmienna ewoluuje do typu bool .

1 struct Base { virtual ~Base(){} };2 struct Derived : Base { virtual void name(){} };3 int main(){4 Base* b1 = new Base;5 if(Derived* d = dynamic_cast<Derived*>(b1)) d->name(); // Sukces6 }

Jeśli wynik dynamicznego rzutowanie w dół występującego wwierszu nr 5 zakończy się sukcesem, to zostanie wykonanametoda name() .

W przeciwnym przypadku dynamic cast zwróci nullptr i

metoda name() nie zostanie wywołana.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 9 / 29

Instrukcja constexpr if

Instrukcja zaczynająca się od if constexpr jest znana jakoconstexpr if.W instrukcji tej wartość warunku musi być skonwertowanymkontekstowo stałym wyrażeniem typu bool .Jeśli wartość jest prawdą, to instrukcja występująca po elsejest odrzucana (jeśli istnieje), w przeciwnym razie wyrażenie poif constexpr jest odrzucane.

template <typename T> auto getValue(T t) {if constexpr (is_pointer_v<T>) return *t;else return t; }

Podany przykładowy szablon funkcji getValue sprawdza czytyp zmiennej t jest typem wskaźnikowym T* czypodstawowym T i w obu przypadkach zwraca wartość.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 10 / 29

Switch z inicjalizatorami zmiennych

Podobnie jak instrukcja if również instrukcja switch otrzymaław dialekcie C++17 możliwość inicjalizacji zmiennych wewnątrznawiasu zawierającego zmienną decyzyjną.

int iT[] = {1, 2, 3};switch(auto [a,b,c] = iT; c){case 1: cout << 1 << '\n'; break;default: cout << "to nie 1 \n"; }

W podanym przykładzie zmienne a , b i c mają charakterlokalny - tak więc obie instrukcje switch :

switch ( instrukcja_init; warunek ) instrukcje;{ instrukcja_init;switch ( warunek ) instrukcje; }

są równoważne.Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 11 / 29

Statyczne pola wbudowane

Pole statyczne może zostać zadeklarowane jako inline .Statyczne pole inline może zostać zdefiniowane wewnątrzklasy i może posiadać inicjalizator.Pole inline static nie wymaga definicji poza klasą.

class mojaKlasa{static int mojePoleStat= 1;inline static int mojePoleInlineStat = 1;

};int mojaKlasa::mojePoleStat = 1;int mojaKlasa::mojePoleInlineStat = 1;

Próba inicjalizacji statycznego pola wbudowanego w sposóbklasyczny powoduje błąd kompilacji.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 12 / 29

Agregaty i ich inicjalizacja

Standard C++ zakłada możliwość blokowej inicjalizacjiniestatycznych pól obiektów za pomocą listy inicjalizatorów podwarunkiem, że spełniają one warunki stawiane agregatom.

Typ obiekt = {arg1, arg2, ...};Typ obiekt {arg1, arg2, ...}; // począwszy od C++11

Pola statyczne są przy takiej inicjalizacji pomijane, przykładowo:

struct S{int i1, i2; static int i3, double d;};S s1 = {1, 2, 3.};S s2[] = {1, 2, 3.,4 ,5 ,6.};cout << s2[1].d << endl; // strumień wyjściowy: 6.

Próba inicjalizacji obiektów, które nie są agregatami powodujebłąd kompilacji.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 13 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,

5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,

5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,

5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,

5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,

5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,

5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,

5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,

5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

Kolejne wersje systemu zmieniały definicję agregatuAgregatem (albo skupiskiem danych) nazywamy:1 typ tablicowy,2 typ klasy (zazwyczaj: struct lub union ) spełniający

warunki:brak prywatnych lub chronionych niestatycznych pól,brak konstruktorów deklarowanych przez użytkownika (wersje doC++11 ),

brak konstruktorów: definiowanych przez użytkownika zwyjątkiem opatrzonych specyfikatorami: default lub delete(wersje od C++11 do C++17 ),brak konstruktorów definiowanych przez użytkownika,dziedziczonych i typu explicit z wyjątkiem opatrzonych

specyfikatorami: default lub delete (wersje od C++17 ).3 brak wirtualnych, prywatnych lub chronionych klas bazowych

(od C++17 ),4 brak funkcji wirtualnych,5 brak inicjalizatorów pól (wersje od C++11 do C++14 ).

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 14 / 29

Agregaty i ich inicjalizacja

C++17 pozwala na inicjalizację pól: agreagatów i ich klasbazowych za pomocą listy inicjalizatorów z listamizagnieżdżonymi.Nie każda klasa bazowa musi być agregatem, ale odpowiadającajej zagnieżdżona lista inicjalizatorów musi być pusta.Inicjalizacja następuje wtedy za pomocą konstruktora lubindywidulanych inicjalizatrów pól.

struct bs1 { int b1, b2 = 42; }; // agregatstruct bs2 { bs2(): b3(42){} int b3; }; // nie-agregatstruct deri : bs1, bs2 { int d; }; // C++17 agregatderi d1{{1, 2}, {}, 4}; // b1 = 1, b2 = 2, b3 = 42, d = 4deri d2{{}, {}, 4}; // b1 = 0, b2 = 42, b3 = 42, d = 4

Listy zagnieżdżone nie są wymagane, gdy ich brak nie wpływa nakolejności inicjalizacji.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 15 / 29

Copy elision

Wraz z możliwością przenoszenia r-wartości w standarcie C++11zyskał na znaczeniu problem optymalizacji funkcji zwracającejobiekt techniką RVO (Return Value Optimization).RVO , czyli optymalizacja wartości zwracanej przez funkcję jest

techniką pozwalającą kompilatorowi konstruować chwilowy i niezwiązany żadną referencją obiekt bez nazwy bezpośrednio wmiejscu wywołania funkcji.

BigData func(){ return BigData(); }

Alternatywą dla tej techniki jest klasyczne utworzenie przezfunkcję obiektu tymczasowego bez nazwy, a następnieskopiowanie tego obiektu do miejsca wywołania funkcji.Druga z wymienionych technik jest szczególnie niekorzystna dlaobiektów o dużych rozmiarach ze względu na dodatkowy czastracony na kopiowanie.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 16 / 29

Copy elision i RVO

Technika pomijania wywołań konstruktorów kopiujących, a takżeod czasu wprowadzenie standardu C++11 konstruktorówprzenoszących, nazywana jest również copy elision .

Prowadzi to do semantyki przesyłania obiektu zwracanego przezwartość bez kopiowania, nawet jeśli występują przy tymzauważalne efekty uboczne.

class BigData{ public:BigData(){} // konstruktor domyślnyBigData(const BigData&){} }; // konstruktor kopiujący

BigData func(){return BigData(); }

int main(){BigData b = func();return 0; }

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 17 / 29

Copy elision i RVO

Istnieje również odmienny wariant copy elision zwany NRVO(Named Return Value Optimization).Dotyczy on przypadku gdy zwracany jest posiadający nazwęautomatyczny obiekt utworzony wewnątrz funkcji.

BigData func(){BigData() b = {};return b; }

Zwracany obiekt nie może być typu volatile ani parametreminstrukcji catchPoprzednie standarty pozwalały na wyłączenie mechanizmucopy elision w zleżności od opcji kompilatora

W standarcie C++17 copy elision stało się obowiązkowe

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 18 / 29

Nowe atrybuty

Standard C++11 wprowadził również możliwość stosowania tzw.atrybutów.

Są to ujęte w podwójny nawias kwadratowy listy słówkluczowych charakteryzujących funkcje, typy, obiekty, kody, itp.

[[deprecated("use double in the future")]]float fun(float x){return x*x;}

Standard C++17 rozszerzył semantykę stosowania atrybutów omożliwość definiowania ich w odpowiednich przestrzeniach nazw:

// dwie równoważne deklaracje:[[using CC: opt(1), debug]][[CC::opt(1), CC::debug]]

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 19 / 29

Nowe atrybuty

Atrybuty zapewniają ujednoliconą standardową składnię dlarozszerzeń językowych definiowanych przez implementację,takich jak rozszerzenia językowe GNU czy IBM .Atrybut może być używany prawie wszędzie w programie C++ istosowany do prawie wszystkiego: do typów, zmiennych, funkcji,nazw, bloków kodu,a nawet do całych jednostek translacyjnych.Jednak każdy poszczególny atrybut jest ważny tylko tam, gdziejest jest to dozwolone - np [[fallthrough]] może byćużywany tylko wraz z instrukcją switch .Atrybuty mogą pojawiać się zarówno przed całą deklaracją, jak ibezpośrednio po nazwie deklarowanej jednostki:

float fun [[deprecated("use double in the future")]](float x){return x*x;}

Nieznane atrybuty są ignorowane.Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 20 / 29

Nowe atrybuty

Dialekt C++17 wprowadził trzy nowe atrybuty standardowe[[fallthrough]]

¯wskazuje na zamierzony brak instrukcji break

po instrukcji case i kompilator nie powinien wysyłać ostrzeżeń.[[nodiscard]] zachęca kompilator do wydania ostrzeżenia,

jeśli wartość zwracana przez funkcję zostanie odrzucona.[[maybe unused]] blokuje ostrzeżenia kompilatora dla

nieużywanych encji, jeśli takie istnieją.

[[nodiscard]] int Compute();int main() {// brak ostrzeżenia o nieużuciu encji i[[maybe_unused]] int i = Compute();

// ostrzeżenie o odrzuceniu wartości zwracanejCompute();

}

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 21 / 29

Zagnieżdżone przestrzenie nazw

Standard C++ umożliwia zagnieżdżanie przestrzeni nazw.

namespace nam2{int f2(){return 2;}namespace nam1{double f1(){return 1.0;}

}}int main(){cout << nam1::f2() << endl; // Błądcout << nam2::f1() << endl; // Błądcout << nam2::nam1::f1() << endl; // OKreturn 0;

}

Przykładowa przestrzeń nazw nam1 nie jest widoczna w zakresieglobalnym, a encje przestrzeni nam1 nie są widoczne w nam2 .

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 22 / 29

Zagnieżdżone przestrzenie nazw

Standard C++11 wprowadził nowe pojęcie przestrzeni nazw -przestrzenie typu inline namespace .

namespace nam2{int f2(){return 1;}inline namespace inam{bool fi(){return f2();}

}}int main(){cout << inam::fi() << endl; // Błądcout << nam2::fi() << endl; // OKreturn 0;

}

W tym przypadku przestrzeń typu inline o nazwie inam równieżnie jest widoczna w zakresie globalnym, ale encje przestrzeninam2 i inam mają zakres obu tych przestrzeni.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 23 / 29

Zagnieżdżone przestrzenie nazw

Standard C++17 umożliwił nowy sposób definiowaniaprzestrzeni zagnieżdżonych - definicje:

namespace nam1{ ... }namespace nam2::nam1{ ... }

są równoważne:

namespace nam2{...namespace nam1{ ... }

}

Natomiast zakres encji dostępnych wewnątrz obu przestrzeninazw jest identyczny w obu przypadkach.

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 24 / 29

Wyrażenia lambda w C++11

Funkcje lambda pojawiły się w standarcie C++11 , ale każdynowy standart wprowadzał zmiany.Każda definicja funkcji lambda musi się składać z trzech części:

[]: listy przechwytywanych obiektów (ang.: captures).(): parametrów funkcji.{}: ciała funkcji.

auto my_lambda = [](int x) { return x + 1; };

C++11 dopuszczał przechwytywanie automatycznych obiektówzakresu, w którym funkacja lambda była deklarowana:

int main(){int i = 1, j = 2;auto lambda = [i, &j](){ cout << i * j << endl; };lambda();}

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 25 / 29

Wyrażenia lambda w C++11

Przechwytywanie wszystkich obiektów zakresu następuje poprzezkopiowanie [=] lub referencje [&] :

int main(){int i = 1, j = 2;auto lambda1 = [=](){ cout << i * j << endl; };auto lambda2 = [&](){ cout << i * j << endl; };i++;lambda1();lambda2();}

Wynikiem zaprezentowanego kodu jest strumień wyjściowy:

24

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 26 / 29

Wyrażenia lambda w C++14

Standard C++14 dodał do wyrażeń lambda dwie nowe opcje:inicjalizację przechwytywanych obiektów,generyczny charakter parametrów funkcji lambda (typ auto ) -do tej pory musiały być określonego typu.

int i = 1;auto lambda = [&j = i](auto k) { j += k; };lambda(5);cout << i << endl;

Przechwytywana zmienna inicjalizowana musi być referencją typuauto i znana jest tylko w zakresie funkcji lambda.

6

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 27 / 29

Wyrażenia lambda w C++17

Standard C++17 dodaje do wyrażeń lambda dwie nowe cechy:wprowaadza funkcje lambda typu constexpr ,pozwala metodom na przechwytywanie obiektu własnego typu.

Funkcja lambda typu constexpr umożliwia wywołanie funkcji iwykorzystanie jej wyniku do wygenerowania obiektówconstexpr już na etapie kompilacji.

constexpr auto suma =[](int a, int b){ return a + b; };

// Poprawna asercjastatic_assert(suma(3,7) == 10, "3 + 7 == 10");// Błędna asercjastatic_assert(suma(4,5) == 15, "4 + 5 != 15");

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 28 / 29

Wyrażenia lambda w C++17

Przechwycenie obiektu za popmocą *this umożliwiabezpieczne użycie metody lambda nawet po zniszczeniuotaczającego obiektu.

struct my_struct {int i = 5;auto value(); };auto my_struct::value() {auto f = [=, *this](){return this->i;};return f();}

int main() {my_struct mS;cout << mS.value() << endl;return 0;

}

Mirosław Głowacki (AGH, UJK) Programowanie w języku C++ 2018 29 / 29