C++14

C++14  este numele neoficial al versiunii ISO/IEC JTC1 a standardului C++ (nume complet: „ Standardul internațional ISO/IEC 14882:2014(E) Limbajul de programare C++ „) [1] . C++14 poate fi considerat ca o mică extensie a C++11 , care conține în principal remedieri de erori și îmbunătățiri minore. Comitetul de dezvoltare a noilor standarde a publicat proiectul N3690 pe 15 mai 2013 [2] . Proiectul de lucru N3936 a fost publicat pe 2 martie 2014, perioada finală de vot s-a închis pe 15 august 2014, iar rezultatul (aprobarea în unanimitate) a fost anunțat pe 18 august 2014 [3] .

Deoarece dezvoltarea standardului a fost lungă, iar anul lansării versiunii finale nu a fost determinat, numele „C++1y” a fost folosit și în timpul dezvoltării, similar cu modul în care standardul C++11 a fost numit „C+”. +0x" înainte de lansarea sa (lansarea acestei versiuni era așteptată până în 2010).

Caracteristicile limbajului descrise mai jos corespund schiței de lucru N3797 . Pot exista mici diferențe între acestea în comparație cu versiunea finală a standardului .

Schimbări de limbă

Această secțiune introduce noi caracteristici ale limbajului de bază în C++14.

Deducerea tipului returnat pentru funcții

C++11 vă permite să deduceți tipul returnat pentru funcțiile lambda din tipul returnat al unei expresii. C++14 extinde această capacitate la toate funcțiile. Noul standard descrie, de asemenea, inferența de tip pentru funcțiile lambda, cu o altă formă decât return expression;[4] .

Pentru a utiliza inferența automată a tipului de returnare, o funcție trebuie să fie declarată cu tip autoca tip de returnare, dar fără specificatorul de coadă a tipului de returnare C++11:

auto DeduceReturnType (); // tipul de returnare va fi definit mai târziu.

Dacă mai multe expresii sunt returnate în locuri diferite în corpul funcției, toate aceste expresii trebuie să aibă un tip dedus comun [5] .

Funcțiile care folosesc auto-inferența de tip return pot folosi declarația forward, dar pot fi utilizate numai după ce au fost definite. Aceste definiții trebuie să fie disponibile în aceeași unitate de traducere în care sunt utilizate.

Este posibil să se folosească recursiunea în astfel de funcții , dar apelul recursiv trebuie făcut după cel puțin o valoare returnată în această funcție [5] :

Auto Corect ( int i ) { dacă ( i == 1 ) intoarce i ; // int este afișat ca tip de returnare altfel return Corect ( i -1 ) + i ; // acum poți suna } autoWrong ( int i ) { _ dacă ( i != 1 ) return Wrong ( i -1 ) + i ; // loc nepotrivit pentru recursivitate. Fără returnare prealabilă. altfel intoarce i ; // int este afișat ca tip de returnare }

Inferență de tip alternativ când se declară

C++11 a adăugat două moduri de a deduce tipuri. autov-a permis să creați variabile cu un tip bazat pe o expresie atribuită. decltypepermis să se determine tipul rezultat al unei expresii arbitrare. Cu toate acestea, tipurile deduse decltypeși autodiferă unele de altele. În special, autodeduce întotdeauna un tip non-referință ca și cum ar fi procesat std::remove_reference, în timp ce auto&&deduce întotdeauna un tip de referință. Cu toate acestea, rezultatul decltypepoate fi fie un tip de referință, fie un tip non-referință, în funcție de expresia care este procesată [4] :

int i ; int && f (); autox3a = i ; _ // decltype(x3a) - int decltype ( i ) x3d = i ; // decltype(x3d) - int auto x4a = ( i ); // decltype(x4a) - int decltype (( i )) x4d = ( i ); // decltype(x4d) - int& auto x5a = f (); // decltype(x5a) - int decltype ( f ()) x5d = f (); // decltype(x5d) - int&&

C++14 a adăugat sintaxa decltype(auto). Această sintaxă vă permite să utilizați reguli de decltypedeclarare auto. Are sens doar în codul standard.

Sintaxa decltype(auto)poate fi, de asemenea, utilizată pentru a deduce tipuri de returnare prin specificarea tipului de returnare al funcției în decltype(auto)loc autode în loc [5] .

Reducerea restricțiilor privind expresiile constante

C++11 introduce conceptul de constexpr-funcții: funcții care pot fi executate în timpul compilării. Valorile pe care le returnează pot fi folosite în operațiuni care necesită o expresie constantă, cum ar fi un argument șablon. Cu toate acestea, în C++11 constexpr, -funcțiile pot conține o singură expresie returnată (precum și static_assertalte câteva declarații).

În C++14, aceste restricții sunt parțial ridicate. constexpr-funcțiile pot conține acum următoarele elemente [4] :

  • Orice anunt altul decat:
    • staticsau thread_localvariabile;
    • declarații de variabile fără inițializatori.
  • Instrucțiuni de ramură condiționată ifși switch.
  • Toate instrucțiunile buclei, inclusiv cele forpentru intervale.
  • Expresii care modifică valorile obiectelor dacă durata de viață a acestor obiecte a început în constexprfuncția -. Aceasta include, de asemenea, apeluri către orice const constexprfuncții membre non-statice.

Declarația gotonu este permisă într-o constexprfuncție C++14.

Restricțiile privind apelarea non- constexprfuncțiilor rămân în vigoare. Astfel, dacă sunt folosite forpentru intervale, funcțiile beginși endcontainerele trebuie supraîncărcate ca constexpr. Pentru un tip încorporat std::initializer_list, funcțiile sunt begin/enddefinite ca constexpr, atât la nivel local, cât și global.

De asemenea, în C++11, toate metodele nestatice declarate cu constexprau fost tratate implicit ca constfuncții - în raport cu this. Această restricție a fost eliminată; metodele non-statice pot fi acum non- const[6] . Cu toate acestea, așa cum am menționat mai devreme, o non- const constexprmetodă poate schimba câmpurile de clasă numai dacă durata de viață a acelui obiect a început în timpul evaluării unei expresii constante.

Șabloane variabile

În versiunile anterioare de C++ , șablonul era limitat la funcții și clase. C++14 vă permite să creați variabile șablon.

template < typenameT > _ constexpr T pi = T ( 3,1415926535897932385 ); // Se aplică regulile uzuale de specializare: template <> constexpr const char * pi < const char *> = "pi" ;

În acest exemplu, este definit un șablon variabil picare poate fi accesat pentru a obține valoarea lui pi pentru diferite tipuri (de exemplu, 3la citirea unui tip întreg; cea mai apropiată valoare de float, doublesau long doublela citirea ca float, doublesau long doublerespectiv , etc.).

Astfel de declarații și definiții includ regulile șablon obișnuite, inclusiv regulile de specializare [7] [8] .

Inițializarea agregată a claselor cu inițializatoare de câmp

C++11 a introdus inițializatori de câmpuri de clasă, care sunt expresii care se aplică câmpurilor la nivel de clasă dacă constructorul nu le inițializează singur. Definiția agregatelor a fost modificată pentru a exclude în mod explicit toate clasele cu inițializatori de membri, astfel încât inițializarea agregatelor nu a fost posibilă pentru acestea.

C++14 elimină această restricție [4] și permite inițializarea agregată a claselor cu inițializatoare de câmp. Dacă lista de inițializatori în acolade nu oferă o valoare pentru acest argument, atunci inițializatorul de câmp [9] preia .

Literale binare

Literale numerice în C++14 pot fi specificate în formă binară [4] . Sintaxa folosește prefixele 0bsau 0B. Sintaxă similară este folosită și în Java , Python , Perl și D.

Mii de separatori

În C++14, puteți folosi apostroful pentru a separa în mod arbitrar biții în literale numerice [10] . În unele cazuri, acest lucru simplifică percepția unor constante numerice mari în cod și îmbunătățește lizibilitatea codului.

auto integer_literal = 1'000'000 ; auto floating_point_literal = 0.000'015'3 ; auto binary_literal = 0b0100'1100'0110 ; auto silly_example = 1'0'0'000'00 ;

Funcții lambda generice

În C++11, parametrii funcției lambda trebuiau declarați cu anumite tipuri. C++14 elimină această restricție și permite ca parametrii funcției lambda să fie declarați cu un specificator de tip auto[7] .

auto lambda = []( auto x , auto y ) { return x + y ;};

Inferența de tip pentru parametrii funcțiilor lambda generice urmează reguli similare cu inferența de tip pentru autovariabile (dar nu complet identice). Codul de mai sus este echivalent cu următorul [11] :

struct unnamed_lambda { template < nume de tip T , nume de tip U > operator automat ()( T x , U y ) const { return x + y ;} }; auto lambda = unnamed_lambda ();

Capturarea expresiilor pentru funcțiile lambda

Funcțiile lambda C++11 vă permit să capturați variabilele declarate într-un domeniu exterior prin trecerea prin referință sau după valoare. Aceasta înseamnă că nu puteți captura prin valoare variabile de tipuri care pot fi doar mutate (dar nu copiate) [12] . C++14 vă permite să capturați variabile cu inițializarea expresiei arbitrare. Acest lucru face posibilă capturarea variabilelor cu mișcare de valori și declararea variabilelor cu nume nedeclarate în domenii superioare [7] .

Expresiile sunt capturate folosind inițializatoare:

auto lambda = [ value = 1 ] { return value ;};

Funcția lambda lambdava returna 1 deoarece valueinițializatorul corespunzător a fost declanșat pentru parametru. Tipul parametrului capturat este dedus din tipul inițializatorului, similar cu declararea unei variabile cu specificatorul auto.

Această caracteristică poate fi folosită pentru a captura cu mișcare folosind funcția standard std::move:

auto ptr = make_unique < int > ( 10 ); auto lambda = [ value = std :: move ( ptr )] { return * value ;};

Atribut [[deprecated]]

Atributul deprecatedvă permite să marcați entitățile ca învechite. Aceste entități pot fi în continuare accesate, dar este emis un avertisment în timpul compilației. Argumentul deprecatedpoate fi un șir literal care explică motivul deprecierii și/sau posibila înlocuire.

[[ depreciat ]] intf ( ); [[ depreciat ( "g() nu este sigur pentru fire. Folosiți h() în loc de g()" )]] void g ( int & x ); void h ( int & x ); void test () { int a = f (); // avertisment: „f” este depreciat g ( a ); // avertisment: „g” este depreciat: g() nu este sigur pentru fire. Folosiți h() în loc de g() }

Funcții noi în biblioteca standard

Mutexuri și încuietori partajate

C++14 adaugă mutexuri partajate și un nou tip de blocare pentru mutexuri partajate [13] [14] .

Căutare eterogenă în containere asociative

Biblioteca standard C++ definește patru clase de containere asociative. Aceste clase permit utilizatorului să caute valori pe baza unei valori de acest tip. Containerele de hărți permit utilizatorului să specifice o cheie și o valoare, în timp ce caută pe cheie și returnează valoarea. Cu toate acestea, căutarea a fost făcută întotdeauna pe un anumit tip de cheie, fie că este cheia, ca în hartă, sau valoarea în sine, ca în set.

C++14 permite indexarea containerelor asociative după o valoare de tip arbitrar, cu condiția să existe un operator de comparare supraîncărcat care poate compara valoarea acelui tip cu valoarea tipului de cheie al containerului [15] . Acest lucru permite containerelor de hărți cu un tip de cheie să fie indexate prin std::stringexpresii de tip const char*folosind operatorul de comparare supraîncărcat operator<.

Pentru a menține compatibilitatea inversă, căutările eterogene sunt permise numai dacă comparatorul transmis containerului asociativ acceptă o astfel de căutare. Clasele standard de bibliotecă std::less(implicit pentru containerele set și hărți) și std::greaterpermit căutări eterogene [16] .

Literale standard definite de utilizator

C++11 are o sintaxă pentru sufixele literale definite de utilizator, dar niciuna dintre ele nu este folosită în biblioteca standard. C++14 adaugă următoarele literale standard [15] :

  • „s” pentru a crea diferite std::basic_stringtipuri.
  • „h”, „min”, „s”, „ms”, „us” și „ns” pentru a crea intervalele de timp corespunzătoare std::chrono::duration.
string str = „bună lume” s ; crono :: duration dur = 60 s ;

Cele două literale „s” nu se afectează reciproc, deoarece literalul șir funcționează doar pe șiruri, în timp ce al doilea literal funcționează doar pe numere [17] .

Adresarea tuplurilor după tip

std::tuple, introdus în C++11, vă permite să agregați mai multe valori tastate care vor fi indexate în timpul compilării. C++14 extinde funcționalitatea tuplurilor pentru a permite accesarea elementelor unui tuplu nu numai prin index, ci și prin tip [15] . Dacă tuplul conține mai mult de un element de tipul solicitat, căutarea va avea ca rezultat o eroare de compilare [18] :

tuple < șir , șir , int > t ( „foo” , „bar” , 7 ); int i = get < int > ( t ); // i == 7 int j = get < 2 > ( t ); // la fel ca înainte: j == 7 șir s = get < șir > ( t ); // Eroare de timp de compilare din cauza ambiguității

Alte modificări ale bibliotecii standard

std::make_uniquepoate fi folosit în același mod ca și std::make_sharedpentru obiecte std::unique_ptr[7] .

Pentru std::integral_constantadăugată o suprasarcină operator()care returnează o valoare constantă [15] .

Prin analogie cu funcțiile globale std::begin/std::end, s-au adăugat funcții std::cbegin/std::cendcare returnează iteratorii constanți la începutul și la sfârșitul intervalului.

Note

  1. ISO/IEC 14882:2014 - Tehnologia informației - Limbaje de programare - C++ . ISO (14 ianuarie 2014). Data accesului: 26 ianuarie 2015. Arhivat din original la 29 ianuarie 2017.
  2. Proiect de comisie, Standard pentru limbajul de programare C++ (PDF). ISO (15 mai 2013). Preluat la 24 iulie 2014. Arhivat din original la 21 ianuarie 2022.
  3. Sutter, Herb (18 august 2014), Avem C++14! , < https://isocpp.org/blog/2014/08/we-have-cpp14 > . Extras 18 august 2014. Arhivat 19 august 2014 la Wayback Machine 
  4. 1 2 3 4 5 Wong, Michael Vederea de la întâlnirea C++ Standard din aprilie 2013 Partea 3 . C/C++ Cafe (30 aprilie 2013). Consultat la 14 iunie 2013. Arhivat din original la 13 octombrie 2013.
  5. 1 2 3 Merrill, Jason N3638 Deducere tip returnare pentru funcții normale (Reviziunea 5) (17 aprilie 2013). Preluat la 14 iunie 2013. Arhivat din original la 25 august 2013.
  6. Smith, Richard N3652 Relaxing constraints on constexpr functions (18 aprilie 2013). Preluat la 24 iulie 2014. Arhivat din original la 25 august 2013.
  7. 1 2 3 4 Sutter, Emblem Trip Report: ISO C++ Spring 2013 Meeting . isocpp.org (20 aprilie 2013). Preluat la 14 iunie 2013. Arhivat din original la 20 august 2017.
  8. Dos Reis, Gabriel N3651 Variable Templates (Revision 1) (PDF) (19 aprilie 2013). Preluat la 24 iulie 2014. Arhivat din original la 25 august 2013.
  9. Vandevoorde, Daveed; Voutilainen, Ville N3653 Inițializatori și agregate pentru membri (17 aprilie 2013). Preluat la 24 iulie 2014. Arhivat din original la 25 august 2013.
  10. Crowl, Lawrence; Smith, Richard; Snyder, Jeff; Vandevoorde, Daveed N3781 ghilimele simple ca separator de cifre (25 septembrie 2013). Consultat la 15 octombrie 2014. Arhivat din original la 13 aprilie 2014.
  11. Faisal, Vali; Sutter, Iarbă; Abrahams, Dave N3649 Expresii Lambda generice (polimorfe) (Reviziunea 3) (19 aprilie 2013). Preluat la 24 iulie 2014. Arhivat din original la 25 august 2013.
  12. Mutați captura în Lambda . preaplin stiva . Consultat la 24 iulie 2014. Arhivat din original la 24 ianuarie 2013.
  13. ^ Wong, Michael The View from the C++ Standard meeting April 2013 Part 3 . C/C++ Cafe (30 aprilie 2013). Consultat la 14 iunie 2013. Arhivat din original la 13 octombrie 2013.
  14. Howard, Hinnant; Vollmann, Detlef; Boehm, Hans N3659 Blocare partajată în C++ (Reviziunea 2) (19 aprilie 2013). Preluat la 24 iulie 2014. Arhivat din original la 19 august 2013.
  15. 1 2 3 4 Wong, Michael The View from the C++ Standard meeting April 2013 Part 2 . C/C++ Cafe (26 aprilie 2013). Consultat la 14 iunie 2013. Arhivat din original la 13 octombrie 2013.
  16. N3657 Adăugarea unei căutări de comparație eterogene la containerele asociative (rev 4) (19 martie 2013). Preluat la 24 iulie 2014. Arhivat din original la 19 august 2013.
  17. Peter, Sommerlad N3642 Literale definite de utilizator pentru tipurile de biblioteci standard (partea 1 - versiunea 4) (PDF) (18 aprilie 2013). Preluat la 24 iulie 2014. Arhivat din original la 25 august 2013.
  18. ^ Spertus , Mike N3670 Wording for Addressing Tuples by Type: Revizia 2 (19 aprilie 2013). Preluat la 24 iulie 2014. Arhivat din original la 19 august 2013.