C++23

C++23 este standardul așteptat pentru limbajul de programare C++ .

Interzis și eliminat

Eliminat

Interzis

Interdicția a fost ridicată

Limba

Modificări minore

if consteval

Mai devreme , a făcut o funcție încorporată a compilatorului, sa dovedit a fi eronată [12] . De exemplu: std::is_constant_evaluated()

constexpr size_t strlen ( char const * s ) { //dacă constexpr (std::is_constant_evaluated()) { Era, nu a apelat versiunea asamblatorului if consteval { // A devenit pentru ( const char * p = s ; ; ++ p ) { dacă ( * p == '\0' ) { returnează static_cast < std :: size_t > ( p - s ); } } } altfel { __asm__ ( "Ceva optimizat pentru SSE" ); } }

Desigur, compilatorii emit un avertisment, dar nu este evident ce trebuie făcut este corect , altfel versiunea optimizată a asamblatorului nu va rula deloc. if (std::is_constant_evaluated())

Al doilea motiv este interacțiunea dintre și . constexprconsteval

consteval int f ( int i ) { return i ; } constexpr int g ( int i ) { // if (std::is_constant_evaluated()) { Was, not compiled if consteval { // Acum returnează f ( i ) + 1 ; } altfel { întoarcere 42 ; } }

Acest cod nu a fost compilat deloc - nu puteți apela o funcție consteval de aici.

Acoladele din partea de atunci sunt necesare, dar în cealaltă parte pot fi omise. Pare imposibil de scris. Vechea funcție nu este interzisă - extrem de rară, dar necesară. if (consteval && n < 0) {

auto(x) este o copie temporară a unui obiect

O modalitate ușoară de a obține un obiect ca temporar, cum ar fi [12] :

void pop_front_alike ( Container auto & x ) { std :: erase ( x.begin ( ), x.end ( ) , auto ( x.front ( ) ) ) ; }

x.front() - eroare: în funcție de container, această referință se va uita fie la un alt obiect, fie în memoria goală.

Codul de mai jos este corect, dar auditorul poate fi tentat să elimine în mod eronat variabila . a

auto a = x . fata (); std :: erase ( x.begin ( ), x.end ( ) , a ) ;

În programarea șablonului, acest tip poate fi dificil de obținut:

folosind T = std :: decay_t < decltype ( x . front ()) > ; std :: erase ( x.begin ( ), x.end ( ) , T ( x.front ( ) ) ) ;

Numele a fost abandonat din două motive: prvalue este un concept extrem de tehnic și comportament neadecvat pentru matrice (va da un pointer). prvalue_cast

Operație de indexare multidimensională (paranteze pătrate)

Metode existente [13] :

matrice ( 1 , 2 , 3 , 4 , 5 ) = 42 ; // arată groaznic matrice [{ 1 , 2 , 3 , 4 , 5 }] = 42 ; // foarte de neînțeles și neplăcut de scris matrice [ 1 ][ 2 ][ 3 ][ 4 ][ 5 ] = 42 ; // un pic mai bine, dar sub capotă e doar înfiorător

Până acum, doar pentru tipurile personalizate [14] .

int buffer [ 2 * 3 * 4 ] = { }; auto s = mdspan < int , extents < 2 , 3 , 4 >> ( buffer ); s [ 1 , 1 , 1 ] = 42 ;

Diferite biblioteci implementează sintaxa lipsă în moduri diferite, dar, în orice caz, aceasta nu este compatibilă cu sintaxa matricelor standard și face dificilă găsirea automată a erorilor și inline-ul (implantarea unei funcții direct în codul de apelare).

Subiectul discutiei ramane: este necesar pentru matrice standard; dacă să relaxeze cerințele și să-l permită în afara clasei. operator[]

Această opțiune

Una dintre caracteristicile C++ - const-corectness - duce la duplicarea codului sau la metodele de scriere de delegare. Se propune o soluție la aceasta prin șabloane [15]

///// WAS ///// clasa TextBlock { public : char const și operator []( size_t position ) const { // ... returnează text [ poziție ]; } char & operator []( size_t position ) { returnează const_cast < char &> ( static_cast < TextBlock const &> ( aceasta ) [ poziție ] ); } // ... }; ///// DEVENI ///// clasa TextBlock { public : template < typenameSelf > _ auto & operator []( acest Self && self , poziție size_t ) { // ... return self . text [ poziție ]; } // ... };

Metodele de extindere nu sunt încă oferite, dar vor fi posibile în viitor.

Cerințe reduse pentru constexpr

Lista de indulgențe este lungă și este legată de două lucruri:

  • Acum constexpr înseamnă că există cel puțin o cale de execuție posibilă la compilare.
  • Bibliotecile rămân întotdeauna în urma limbii.

Astfel, acum este posibil să scrieți o funcție constexpr care, fără un set de argumente, poate fi executată la compilare [16] .

De asemenea, în funcțiile constexpr sunt permise goto , variabile de tipuri non-literale, variabile statice/intra-thread. Dacă oricare dintre aceste linii este trecută în timpul compilării, funcția este evaluată la execuție. ridicat la 202103L [17] . __cpp_constexpr

Operator static()

Îndepărtează o instrucțiune de mașină dacă clasa nu are date și introducerea eșuează [18] . De exemplu, într-un arbore de auto-echilibrare cu o comandă non-standard (era în C++03 ) și căutare eterogenă ( C++14 ), următorul cod este posibil:

struct CustomCompare { folosind is_transparent = int ; // operator bool static de căutare heterogenă () ( std :: string_view a , std :: string_view b ) // a fost const, a devenit static { return someCustomLess ( a , b ); } }; std :: set < std :: string , CustomCompare > lucruri ;

Codificări de caractere

Caractere permise în identificatori

Caracterele din seturile Unicode XID_Start (start) și XID_Continue (altele) sunt acum permise în identificatori .

  • Sunt permise litere și numere din diferite alfabete, inclusiv caractere chinezești , cuneiforme și litere matematice latine/arabe, multe dintre acestea fiind caractere asemănătoare literelor.
  • Caracterele de tip „litera/modificator” sunt permise - 02C6 ˆ „modifier-cap” este permisă, iar 02DA ˚ „cercul superior” este de tip „caracter/modifier” și este interzisă.
  • Este permisă combinarea mărcilor, inclusiv selectoare de stil.
  • Emoji , caracterele nealfabetice din inginerie și matematică, caracterele de formatare (caracterele invizibile responsabile pentru procesarea textului, inclusiv ZWJ și ZWNJ) sunt interzise .

Identificatorul trebuie normalizat conform algoritmului de „compoziție canonică” (NFC, dezasamblarea caracterelor monolitice în componente și reasamblarea). Dacă nu, programul este incorect.

Această modificare doar face ca suportul Unicode să fie mai consistent, dar nu face nimic pentru a rezolva problemele atacurilor prin șiruri aparent identice [19] . Metodele de transmitere a unor astfel de caractere către linker depind de implementare.

Literele wchar_t cu mai multe caractere și necodate nu sunt permise

Diferiți compilatori au acționat diferit asupra (facepalm emoji ) pe un wchar_t pe dublu octet (Windows), . Ambele sunt acum interzise [20] . L'\U0001F926'L'ab'

Literele cu mai multe caractere încă funcționează, sunt de tip int. Câte caractere sunt permise și cum vor fi colectate într-un singur număr este determinat de implementare.

Conceptele de „codare de traducere”, „codificare de performanță”

Este legal ca unul să fie diferit de celălalt [21] , și  este o unitate a unei codări de performanță largi, specifice implementării [22] . wchar_t

UTF-8 ca codificare de traducere multiplatformă trebuie să fie suportat necondiționat de toți compilatorii [23] . Semnul de ordine al octeților este ignorat, cu excepția cazului în care intră în conflict cu steagurile compilatorului. Dacă fișierul este recunoscut ca UTF-8, nu ar trebui să conțină combinații de coduri incorecte - totuși, pot exista combinații corecte corespunzătoare caracterelor care încă nu există.

Valorile numerice ale caracterelor literale din preprocesor se potrivesc cu codificarea de execuție

Înainte era până la implementare, dar s-a dovedit că scopul principal al acestei funcții este de a determina codificarea execuției [24] . De exemplu, codul din SQLite :

/* Verificați dacă aparatul utilizează EBCDIC. (Da, crezi sau nu, mai există mașini care folosesc EBCDIC.) */ #if 'A' == '\301' # define SQLITE_EBCDIC 1 #else # define SQLITE_ASCII 1 #endif

Toți compilatorii majori funcționează de fapt în acest fel.

Este din nou permisă inițializarea matricelor char și nesemnate cu un literal UTF-8

Toate cele trei linii sunt rupte în C++20, funcționează din nou în C++23 [25] .

const char * a = u8 "a" ; const char b [] = u8 "b" ; const unsigned char c [] = u8 "c" ;

După cum sa dovedit, o astfel de întrerupere a făcut funcțiile constexpr mai complicate și a interferat cu compatibilitatea cu C.

Capturi de ecran noi

"\u{1F926}"pentru un punct de cod Unicode, pentru octal și pentru hexazecimal [26] . "\o{123}""\x{AB}"

Spărgerea unor astfel de scuturi ( ) este interzisă. "\x{4" "2}"

"\N{LATIN CAPITAL LETTER A WITH MACRON}"vă permite să faceți referire la un simbol prin numele său unicode [27] .

Modificări editoriale

  • Concatenarea backslash permite acum spații după backslash [28] . Așa au funcționat GCC, Clang și ICC - iar MSVC a lăsat un gol.
  • Compilatorul nu are voie să rearanjeze câmpurile unui obiect dacă au o lungime diferită de zero și drepturi de acces diferite [29] . Așa au acționat MSVC, GCC, Clang.
  • Concatenarea șirurilor de caractere cu prefixe de codificare conflictuale precum . Dintre compilatoarele majore, doar SDCC acceptă acest lucru  - este nevoie de primul dintre prefixe [30] .L"" u""
  • Directiva legalizată #warningsusținută de toți [31] .
  • Reguli de mutare implicite simplificate la întoarcerea de la o funcție [32] .
  • Tipuri întregi extinse refactorizate specifice furnizorului [33] .
  • S-a clarificat starea fișierelor de antet C: acestea sunt acum pentru compatibilitate inversă. Un fișier care nu trebuie să fie simultan un fișier C valid nu trebuie să le includă [34] .

Armonizare cu C

  • Etichetă fără operator permis: [35] .{ goto a; ++x; a: }
  • Sprijin . Nu există analog [36] .<stdatomic.h><cstdatomic>
  • Este din nou permisă inițializarea matricelor char și nesemnate cu un literal UTF-8 (descris mai sus).

Biblioteca

Modificări minore

  • exchangea primit o condiție noexcept - dacă obiectul este creat cu o mutare și atribuit prin copie fără a arunca excepții [37] .
  • Eterogene și în recipiente asociative [38] . De exemplu, cheia de stocare este , iar cheia de acces este .extracterasestringstring_view
  • string[_view].contains - de multe ori trebuie să verificați prezența unui subșir fără a afla unde este potrivirea [39] .
  • O nouă funcție , care utilizează mai pe deplin caracteristicile mecanismului de alocare a memoriei [40] . Containerele de dimensiuni variabile vor migra treptat către acesta.Allocator.allocate_at_least
  • O familie de constante  - de exemplu, pentru a urmări migrarea unei biblioteci de la vechi la nou [41] .is_scoped_enumenumenum class
  • O funcție de conversie , care este mai ușor de înțeles ca nume și mai puțin predispusă la erori [42] .to_underlyingenum int
  • Funcție din antet pentru a schimba ordinea octeților în numere [43] .byteswap<bit>
  • iostream poate imprima acum pointeri volatili, la fel ca pointerii normali [44] .

std::move_only_function

std::functiona devenit una dintre cele mai „grele” părți ale bibliotecii STL. Scăpând de mai multe caracteristici - nu pot fi copiate, câmpuri lipsă și  - puteți obține un obiect mult mai ușor [45] . Și, desigur, acest obiect poate funcționa cu cârlige care nu pot fi copiate. targettarget_type

Operații Monad pe std::opțional

O monada  este o caracteristică standard a limbajelor funcționale pentru a efectua o secvență de acțiuni.

În matematică, o secvență de funcții este scrisă ca , ceea ce nu este întotdeauna convenabil - în programare, ceva de genul . x.f().g().h()

std::optional  este un înveliș destul de simplu, al cărui sens este de a stoca un obiect sau nimic. Verificările pentru „nimic” ocupă o mare parte a lucrării cu opțional - dar dacă, în procesul de transformare a imaginii, nu există nicio pisică pe ea? Dar dacă nu există loc pentru a trage un arc? [46]

std :: opțional < imagine > get_cute_cat ( const imagine & img ) { return crop_to_cat ( img ) // imagine → opțional; [nullopt] nu există nicio pisică în imagine . and_then ( add_bow_tie ) // imagine → optional; [nullopt] nicăieri pentru a adăuga un arc . and_then ( make_eyes_sparkle ) // imagine → optional; [nullopt] nu poate vedea ochii . transform ( face_mai mic ) // imagine → imagine . transform ( adaugă_curcubeu ); // imagine → imagine }

string::resize_and_overwrite

Folosit pentru optimizare extremă la joncțiunea șirurilor și a API-urilor de nivel scăzut:

int compress ( void * out , size_t * out_size , const void * in , size_t in_size ); std :: string CompressWrapper ( std :: string_view input ) { std :: șir comprimat ; comprimat . resize_and_overwrite ( input . size (), [ input ]( char * buf , std :: size_t n ) noexcept { std :: size_t compressed_size = n ; auto is_ok = compress ( buf , & compressed_size , input . data (), input . size ()); assert ( is_ok ); returnează dimensiunea_comprimată ; }); return comprimat ; }

Apare întrebarea: ce a fost optimizat în comparație cu cele două ? [13] Faptul este că costul alocării memoriei nu depinde mult de lungimea buffer-ului și, în cele mai multe cazuri, va fi alocată memoriei tampon mult mai mult decât este necesar de fapt pentru șirul comprimat. Noua funcție nu inițializează buffer-ul și repunerea la zero a unei secțiuni foarte lungi de memorie - . resizememset( compressed.data(), compressed.size(), '\0')

spanstream - un înlocuitor pentru interzis în C++98 strstream

A existat un strstream - un flux de date care rulează pe o matrice de lungime limitată. Interzis în C++98, a fost propus un alt mecanism similar.

ieșire char [ 30 ]{}; ospanstream os { span < char > { output }}; os << 10 << 20 << 30 ; auto const sp = os . span (); ASSERT_EQUAL ( 6 , dimensiunea sp . ()); ASSERT_EQUAL ( "102030" , std :: șir ( sp . date (), sp . size ())); ASSERT_EQUAL ( static_cast < void *> ( output ), sp . data ()); // nu se copiază datele ASSERT_EQUAL ( "102030" , output ); // nul-terminated garantat

imprimare

Initial a fost:std::cout << std::format("Hello, {}! You have {} mails", username, email_count);

Aceasta…

  • Prelungește codul binar - fluxurile sunt în mod inerent grele.
  • Fără suport Unicode.
  • Arată urât.

Este disponibil unul mai ușor [47] . std::print("Привет, {}! У вас {} писем", username, email_count);

Tipuri fracționale opționale

Nume Bucăți de mantisă ordine de biți Notă
float16_t 10 + implicit 1 5 Respectă IEEE binary16
bfloat16_t 7 + implicit 1 opt Doi octeți superiori IEEE binary32 (≈float), utilizați în bibliotecile AI, de unde și numele brain float
float32_t 23 + implicit 1 opt Conform IEEE binary32, majoritatea implementărilor float
float64_t 52 + implicit 1 unsprezece Conform IEEE binary64, majoritatea implementărilor de dublu
float128_t 112 + implicit 1 cincisprezece Respectă IEEE binary128

Funcțiile matematice trebuie să aibă wrappers pentru toate tipurile suportate - în timp ce calculul real poate fi efectuat într-un tip mai mult sau mai puțin exact [48] .

Note

  1. Sursa . Preluat la 8 august 2022. Arhivat din original la 18 iulie 2022.
  2. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2327r1.pdf
  3. Sursa . Preluat la 20 iulie 2022. Arhivat din original la 10 iunie 2022.
  4. P2360R0: Extindeți instrucțiunea init pentru a permite declarația alias
  5. CWG Numărul 2397
  6. P1102R2: Jos ()! . Preluat la 9 august 2022. Arhivat din original la 9 august 2022.
  7. Sursa . Preluat la 27 iulie 2022. Arhivat din original la 24 mai 2022.
  8. Restrângerea conversiilor contextuale la bool . Preluat la 27 iulie 2022. Arhivat din original la 27 iulie 2022.
  9. Schimbați domeniul de aplicare a tipului de retur-întoarcere lambda . Preluat la 27 iulie 2022. Arhivat din original la 27 iulie 2022.
  10. Sursa . Preluat la 27 iulie 2022. Arhivat din original la 22 august 2022.
  11. Sursa . Preluat la 1 august 2022. Arhivat din original la 30 iulie 2022.
  12. 1 2 `dacă consteval` . Preluat la 20 iulie 2022. Arhivat din original la 20 iulie 2022.
  13. 1 2 C++23 - caracteristică înghețare închidere / Sudo Null IT News Preluat la 28 iulie 2022. Arhivat din original la 14 mai 2022.
  14. Sursa . Preluat la 20 iulie 2022. Arhivat din original la 24 mai 2022.
  15. Deducerea acestui lucru . Preluat la 27 iulie 2022. Arhivat din original la 12 iulie 2022.
  16. Relaxarea unor restricții constexpr . Preluat la 29 iulie 2022. Arhivat din original la 25 iulie 2022.
  17. Variabile non-literale (și etichete și gotos) în funcțiile constexpr . Preluat la 20 iulie 2022. Arhivat din original la 24 mai 2022.
  18. operator static() . Preluat la 29 iulie 2022. Arhivat din original la 29 iulie 2022.
  19. Sintaxa identificatorului C++ folosind standardul Unicode Anexa 31 . Preluat la 27 iulie 2022. Arhivat din original la 12 iulie 2022.
  20. Sursa . Preluat la 27 iulie 2022. Arhivat din original la 27 iulie 2022.
  21. P2314R3: Seturi de caractere și codificări . Preluat la 27 iulie 2022. Arhivat din original la 24 mai 2022.
  22. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2460r2.pdf
  23. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2295r6.pdf
  24. Sursa . Preluat la 27 iulie 2022. Arhivat din original la 24 mai 2022.
  25. D2513R3: char8_t Remediere de compatibilitate și portabilitate
  26. Sursa . Preluat la 29 iulie 2022. Arhivat din original la 24 mai 2022.
  27. Evadările de caractere universale numite . Preluat la 29 iulie 2022. Arhivat din original la 29 iulie 2022.
  28. Sursa . Preluat la 27 iulie 2022. Arhivat din original la 24 mai 2022.
  29. Sursa . Preluat la 27 iulie 2022. Arhivat din original la 24 mai 2022.
  30. P2201R1: Concatenare literală de șiruri mixte . Preluat la 27 iulie 2022. Arhivat din original la 27 iulie 2022.
  31. Sursa . Preluat la 27 iulie 2022. Arhivat din original la 30 iulie 2022.
  32. P2266R3: Mișcare implicită mai simplă . Preluat la 1 august 2022. Arhivat din original la 24 mai 2022.
  33. Curățarea tipurilor de clase întregi
  34. Clarificarea stării „antetelor C”
  35. Sursa . Preluat la 29 iulie 2022. Arhivat din original la 17 iunie 2022.
  36. P0943R6: Suportă atomii C în C. Preluat la 8 august 2022. Arhivat din original la 8 august 2022.
  37. P2401R0: Adăugați o specificație condițională noexcept la std::exchange . Preluat la 28 iulie 2022. Arhivat din original la 28 iulie 2022.
  38. P2077R3: Supraîncărcări eterogene de ștergere pentru containere asociative . Preluat la 29 iulie 2022. Arhivat din original la 24 mai 2022.
  39. șirul conține funcția . Preluat la 8 august 2022. Arhivat din original la 8 august 2022.
  40. P0401R6: Furnizarea de feedback privind dimensiunea în interfața Allocator . Preluat la 8 august 2022. Arhivat din original la 20 iulie 2022.
  41. Sursa . Preluat la 8 august 2022. Arhivat din original la 24 mai 2022.
  42. P1682R3: std::to_underlying pentru enumerari . Preluat la 8 august 2022. Arhivat din original la 8 august 2022.
  43. P1272R4: Byteswapping pentru distracție&&nuf . Preluat la 8 august 2022. Arhivat din original la 8 august 2022.
  44. P1147R1: Tipărirea indicatoarelor „volatile”.
  45. P0288R9: funcția_numai_de_mutare . Preluat la 20 iulie 2022. Arhivat din original la 20 iulie 2022.
  46. p0798R6: Operații monadice pentru std::opțional . Preluat la 20 iulie 2022. Arhivat din original la 20 iulie 2022.
  47. P2093R14: Ieșire formatată . Preluat la 29 iulie 2022. Arhivat din original la 24 iulie 2022.
  48. P1467R9: Tipuri extinse în virgulă mobilă și nume standard . Preluat la 29 iulie 2022. Arhivat din original la 29 iulie 2022.