C++14

C++14  är det inofficiella namnet på ISO/IEC JTC1- versionen av C++- standarden (fullständigt namn: " International Standard ISO/IEC 14882:2014(E) Programming Language C++ ") [1] . C++14 kan ses som en liten förlängning av C++11 som innehåller mestadels buggfixar och mindre förbättringar. New Standard Development Committee publicerade utkastet N3690 den 15 maj 2013 [2] . Arbetsutkastet N3936 publicerades den 2 mars 2014, den sista omröstningsperioden avslutades den 15 augusti 2014 och resultatet (enhälligt godkännande) tillkännagavs den 18 augusti 2014 [3] .

Eftersom utvecklingen av standarden var lång och året för utgivningen av den slutliga versionen inte fastställdes, användes även namnet "C++1y" under utvecklingen, liknande hur C++11-standarden kallades "C+ +0x" innan den släpptes (släppningen av denna version förväntades till 2010).

Språkfunktionerna som beskrivs nedan motsvarar arbetsutkastet N3797 . Det kan finnas små skillnader i dessa jämfört med den slutliga versionen av standarden .

Språkändringar

Det här avsnittet introducerar nya centrala språkfunktioner i C++14.

Returtyp slutledning för funktioner

C++11 låter dig härleda returtypen för lambdafunktioner från returtypen för ett uttryck. C++14 utökar denna möjlighet till alla funktioner. Den nya standarden beskriver också typinferens för lambdafunktioner, med en annan form än return expression;[4] .

För att kunna använda automatisk returtypinferens måste en funktion deklareras med typ autosom returtyp, men utan C++11 returtypsspecifikation:

auto DeduceReturnType (); // returtyp kommer att definieras senare.

Om flera uttryck returneras på olika ställen i funktionens brödtext måste alla dessa uttryck ha en gemensam infererad typ [5] .

Funktioner som använder returtyp auto-inferens kan använda framåtdeklaration, men de kan endast användas efter att de har definierats. Dessa definitioner måste finnas tillgängliga i samma översättningsenhet som de används i.

Det är möjligt att använda rekursion i sådana funktioner , men det rekursiva anropet måste göras efter minst ett returvärde i denna funktion [5] :

autokorrigering ( int i ) { _ om ( i == 1 ) returnera i ; // int visas som returtyp annars returnera Rätt ( i -1 ) + i ; // nu kan du ringa } autoFel ( int i ) { _ om ( i != 1 ) return Fel ( i -1 ) + i ; // olämplig plats för rekursion. Ingen tidigare retur. annan returnera i ; // int visas som returtyp }

Alternativ typinferens vid deklarering av

C++11 lade till två sätt att härleda typer. autotillät dig att skapa variabler med en typ baserad på ett tilldelat uttryck. decltypetillåts bestämma den resulterande typen av ett godtyckligt uttryck. Men de typer som härleddes av decltypeoch autoskilde sig från varandra. I synnerhet autosluter den alltid en icke-referenstyp som om den bearbetades std::remove_reference, medan den auto&&alltid härleder en referenstyp. Men resultatet decltypekan vara antingen en referenstyp eller en icke-referenstyp, beroende på vilket uttryck som bearbetas [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 lade till syntaxen decltype(auto). decltypeDenna syntax låter dig använda deklarationsregler auto. Det är bara vettigt i boilerplate-kod.

Syntaxen decltype(auto)kan också användas för att härleda returtyper genom att ange funktionens returtyp decltype(auto)istället autoför på plats [5] .

Minska restriktioner för konstanta uttryck

C++11 introducerar konceptet constexpr-funktioner: funktioner som kan köras vid kompilering. Värdena de returnerar kan användas i operationer som kräver ett konstant uttryck, till exempel som ett mallargument. Men i C++11 constexprkan -funktioner endast innehålla ett returuttryck (liksom static_assertflera andra deklarationer).

I C++14 är dessa restriktioner delvis upphävda. constexpr-funktioner kan nu innehålla följande element [4] :

  • Något annat meddelande än:
    • staticeller thread_localvariabler;
    • variabeldeklarationer utan initialiserare.
  • Villkorliga greninstruktioner ifoch switch.
  • Alla loopinstruktioner, inklusive de forför intervall.
  • Uttryck som ändrar objektens värden om livslängden för dessa objekt började i constexpr-funktionen. Detta inkluderar även anrop till alla icke const constexpr-statiska medlemsfunktioner.

Uttrycket gotoär inte tillåtet i en constexprC++14 -funktion.

Restriktioner för att ringa icke- constexpr-funktioner förblir i kraft. Således, om de används forför intervall, måste funktioner beginoch behållare överbelastas som constexpr. endFör en inbyggd typ definieras std::initializer_listfunktioner begin/endsom constexpr, både lokalt och globalt.

Dessutom, i C++11, behandlades alla icke-statiska metoder som deklarerats med constexprimplicit som const-funktioner med avseende på this. Denna begränsning har tagits bort; icke-statiska metoder kan nu vara icke- const[6] . Men, som tidigare nämnts, kan en icke const constexpr-metod endast ändra klassfält om objektets livslängd började under utvärderingen av ett konstant uttryck.

Variabel mallar

I tidigare versioner av C++ var mallar begränsad till funktioner och klasser. C++14 låter dig skapa mallvariabler.

mall < typnamnT > _ constexpr T pi = T ( 3,1415926535897932385 ); // Vanliga specialiseringsregler gäller: mall <> constexpr const char * pi < const char *> = "pi" ;

I det här exemplet definieras en variabelmall pisom kan nås för att få värdet på pi för olika typer (till exempel 3när man läser en heltalstyp; närmast värdet float, doubleeller long doublenär man läser som float, doubleeller long double, respektive, etc.).

Sådana deklarationer och definitioner inkluderar de vanliga mallreglerna, inklusive specialiseringsregler [7] [8] .

Aggregerad initiering av klasser med fältinitierare

C++11 introducerade klassfältinitierare, som är uttryck som gäller för fält på klassnivå om konstruktorn inte initierar dem på egen hand. Definitionen av aggregat ändrades för att explicit utesluta alla klasser med medlemsinitierare, så aggregatinitiering var inte möjlig för dem.

C++14 tar bort denna begränsning [4] och tillåter aggregerad initiering av klasser med fältinitierare. Om listan med initierare i klammerparenteser inte ger ett värde för detta argument, tar fältinitieraren [9] över .

Binära bokstaver

Numeriska bokstaver i C++14 kan anges i binär form [4] . Syntaxen använder prefixen 0beller 0B. Liknande syntax används också i Java , Python , Perl och D.

Tusen avgränsare

I C++14 kan du använda apostrof för att godtyckligt separera bitar i numeriska bokstaver [10] . I vissa fall förenklar detta uppfattningen av stora numeriska konstanter i koden och förbättrar kodens läsbarhet.

auto heltal_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 ;

Generiska lambdafunktioner

I C++11 måste lambdafunktionsparametrar deklareras med specifika typer . C++14 tar bort denna begränsning och tillåter lambdafunktionsparametrar att deklareras med en typspecifikation auto[7] .

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

Typinferens för parametrar för generiska lambdafunktioner följer regler som liknar typinferens för auto-variabler (men inte helt identiska). Ovanstående kod motsvarar följande [11] :

struct namnlös_lambda { mall < typnamn T , typnamn U > auto operator ()( T x , U y ) const { return x + y ;} }; auto lambda = namnlös_lambda ();

Fånga uttryck för lambda-funktioner

C++11 lambda-funktioner låter dig fånga variabler som deklareras i ett yttre omfång genom att skicka med referens eller värde. Detta innebär att du inte kan fånga med värdevariabler av typer som bara kan flyttas (men inte kopieras) [12] . C++14 låter dig fånga variabler med godtycklig uttrycksinitiering. Detta gör det möjligt att fånga variabler med värderörelse och att deklarera variabler med namn som inte deklareras i högre scopes [7] .

Uttryck fångas med hjälp av initialiserare:

auto lambda = [ värde = 1 ] { returvärde ; };

Lambdafunktionen lambdakommer att returnera 1 eftersom valuelämplig initialiserare har utlösts för parametern. Typen av den infångade parametern härleds från typen av initialiserare, på samma sätt som att deklarera en variabel med specifikationen auto.

Denna funktion kan användas för att fånga med rörelse med standardfunktionen std::move:

auto ptr = make_unique < int > ( 10 ); auto lambda = [ värde = std :: flytta ( ptr )] { return * värde ;};

Attribut [[deprecated]]

Attributet deprecatedlåter dig markera enheter som föråldrade. Dessa enheter kan fortfarande nås, men en kompileringsvarning utfärdas. Argumentet deprecatedkan vara en bokstavlig sträng som förklarar utfasningsorsaken och/eller möjlig ersättning.

[[ utfasad ]] intf ( ); [[ utfasad ( "g() är inte trådsäker. Använd h() istället för g()" )]] void g ( int & x ); void h ( int & x ); void test () { int a = f (); // varning: 'f' är utfasad g ( a ); // varning: 'g' är utfasad: g() är inte trådsäker. Använd h() istället för g() }

Nya funktioner i standardbiblioteket

Delade mutexer och lås

C++14 lägger till delade mutexar och en ny låstyp för delade mutexar [13] [14] .

Heterogen sökning i associativa behållare

C++ Standardbiblioteket definierar fyra associativa containerklasser. Dessa klasser tillåter användaren att söka efter värden baserat på ett värde av den typen. Kartbehållare låter användaren ange en nyckel och ett värde, samtidigt som han söker på nyckeln och returnerar värdet. Uppslagningen har dock alltid gjorts på en viss typ av nyckel, oavsett om det är nyckeln, som i kartan, eller själva värdet, som i set.

C++14 tillåter att associativa behållare indexeras med ett värde av en godtycklig typ, förutsatt att det finns en överbelastad jämförelseoperator som kan jämföra värdet på den typen med värdet på behållarens nyckeltyp [15] . Detta gör att kartbehållare med en nyckeltyp kan indexeras med std::stringtyputtryck const char*med den överbelastade jämförelseoperatorn operator<.

För att upprätthålla bakåtkompatibilitet tillåts heterogena sökningar endast om komparatorn som skickas till den associativa behållaren stöder en sådan sökning. Standardbiblioteksklasser std::less(standard för set- och kartbehållare) och std::greatertillåter heterogena sökningar [16] .

Standard användardefinierade bokstaver

C++11 har en syntax för användardefinierade bokstavliga suffix, men inget av dem används i standardbiblioteket. C++14 lägger till följande standardliteraler [15] :

  • "s" för att skapa olika std::basic_stringtyper.
  • "h", "min", "s", "ms", "oss" och "ns" för att skapa motsvarande tidsintervall std::chrono::duration.
string str = "hej världen" s ; chrono :: varaktighet dur = 60 s ;

De två "s"-literalerna påverkar inte varandra eftersom strängliteralen bara fungerar på strängar, medan den andra bokstavligen bara fungerar på siffror [17] .

Adressering av tuplar efter typ

std::tuple, introducerad i C++11, låter dig aggregera flera skrivna värden som kommer att indexeras vid kompilering. C++14 utökar funktionaliteten för tupler för att tillåta åtkomst av element i en tupel inte bara genom index, utan också efter typ [15] . Om tuplen innehåller mer än ett element av den begärda typen, kommer uppslagningen att resultera i ett kompileringsfel [18] :

tupel < sträng , sträng , int > t ( "foo" , "bar" , 7 ); int i = get < int > ( t ); // i == 7 int j = get < 2 > ( t ); // samma som tidigare: j == 7 sträng s = < sträng > ( t ); // kompileringstidsfel på grund av oklarhet

Andra ändringar i standardbiblioteket

std::make_uniquekan användas på samma sätt som std::make_sharedför objekt std::unique_ptr[7] .

För std::integral_constanttillagd en överbelastning operator()som returnerar ett konstant värde [15] .

I analogi med globala funktioner std::begin/std::endhar funktioner lagts till std::cbegin/std::cendsom returnerar konstanta iteratorer till början och slutet av intervallet.

Anteckningar

  1. ISO/IEC 14882:2014 - Informationsteknik - Programmeringsspråk - C++ . ISO (14 januari 2014). Datum för åtkomst: 26 januari 2015. Arkiverad från originalet 29 januari 2017.
  2. Kommittéutkast, standard för programmeringsspråk C++ (PDF). ISO (15 maj 2013). Hämtad 24 juli 2014. Arkiverad från originalet 21 januari 2022.
  3. Sutter, Herb (18 augusti 2014), Vi har C++14! , < https://isocpp.org/blog/2014/08/we-have-cpp14 > . Hämtad 18 augusti 2014. Arkiverad 19 augusti 2014 på Wayback Machine 
  4. 1 2 3 4 5 Wong, Michael Utsikten från C++-standardmötet april 2013 del 3 . C/C++ Café (30 april 2013). Hämtad 14 juni 2013. Arkiverad från originalet 13 oktober 2013.
  5. 1 2 3 Merrill, Jason N3638 Avdrag för returtyp för normala funktioner (Revision 5) (17 april 2013). Hämtad 14 juni 2013. Arkiverad från originalet 25 augusti 2013.
  6. Smith, Richard N3652 Avslappnande begränsningar för constexpr-funktioner (18 april 2013). Hämtad 24 juli 2014. Arkiverad från originalet 25 augusti 2013.
  7. 1 2 3 4 Sutter, Emblem Trip Report: ISO C++ Vårmöte 2013 . isocpp.org (20 april 2013). Hämtad 14 juni 2013. Arkiverad från originalet 20 augusti 2017.
  8. Dos Reis, Gabriel N3651 Variable Templates (Revision 1) (PDF) (19 april 2013). Hämtad 24 juli 2014. Arkiverad från originalet 25 augusti 2013.
  9. Vandevoorde, Daveed; Voutilainen, Ville N3653 Medlemsinitierare och aggregat (17 april 2013). Hämtad 24 juli 2014. Arkiverad från originalet 25 augusti 2013.
  10. Crowl, Lawrence; Smith, Richard; Snyder, Jeff; Vandevoorde, Daveed N3781 Single-Citat-Mark as a Digit Separator (25 september 2013). Hämtad 15 oktober 2014. Arkiverad från originalet 13 april 2014.
  11. Faisal, Vali; Sutter, Ört; Abrahams, Dave N3649 Generiska (polymorfa) lambdauttryck (revision 3) (19 april 2013). Hämtad 24 juli 2014. Arkiverad från originalet 25 augusti 2013.
  12. Flytta fångst i Lambda . stack overflow . Hämtad 24 juli 2014. Arkiverad från originalet 24 januari 2013.
  13. Wong, Michael Utsikten från C++ Standard-mötet april 2013 del 3 . C/C++ Café (30 april 2013). Hämtad 14 juni 2013. Arkiverad från originalet 13 oktober 2013.
  14. Howard, Hinnant; Vollmann, Detlef; Boehm, Hans N3659 Delad låsning i C++ (Revision 2) (19 april 2013). Hämtad 24 juli 2014. Arkiverad från originalet 19 augusti 2013.
  15. 1 2 3 4 Wong, Michael Utsikten från C++-standardmötet april 2013 Del 2 . C/C++ Café (26 april 2013). Hämtad 14 juni 2013. Arkiverad från originalet 13 oktober 2013.
  16. N3657 Lägger till heterogen jämförelseuppslag till associativa behållare (rev 4) (19 mars 2013). Hämtad 24 juli 2014. Arkiverad från originalet 19 augusti 2013.
  17. Peter, Sommerlad N3642 Användardefinierade bokstaver för standardbibliotekstyper (del 1 - version 4) (PDF) (18 april 2013). Hämtad 24 juli 2014. Arkiverad från originalet 25 augusti 2013.
  18. Spertus, Mike N3670 Formulering för att adressera tupler efter typ: Revision 2 (19 april 2013). Hämtad 24 juli 2014. Arkiverad från originalet 19 augusti 2013.