C++23

C++23 je očekávaným standardem pro programovací jazyk C++ .

Zakázáno a odstraněno

Odebráno

Zakázáno

Zákaz zrušen

Jazyk

Drobné změny

if consteval

Dřívější , vytvořená jako vestavěná funkce kompilátoru, se ukázala jako chybná [12] . Například: std::is_constant_evaluated()

constexpr size_t strlen ( char const * s ) { //if constexpr (std::is_constant_evaluated()) { Bylo, nevolalo verzi assembleru if consteval { // Stalo se pro ( const char * p = s ; ; ++ p ) { if ( * p == '\0' ) { return static_cast < std :: size_t > ( p - s ); } } } jinak { __asm__ ( "Něco optimalizovaného pro SSE" ); } }

Kompilátory samozřejmě vydávají varování, ale není zřejmé, co dělat je správné , jinak optimalizovaná verze assembleru vůbec nepoběží. if (std::is_constant_evaluated())

Druhým důvodem je interakce mezi a . constexprconsteval

consteval int f ( int i ) { return i ; } constexpr int g ( int i ) { // if (std::is_constant_evaluated()) { Bylo, nezkompilováno if consteval { // Nyní return f ( i ) + 1 ; } jinak { návrat 42 ; } }

Tento kód se vůbec nezkompiloval – odtud nemůžete volat funkci consteval.

Složené závorky v tehdejší části jsou povinné, ale v jiné části je lze vynechat. Zdá se nemožné psát. Stará funkce není zakázána - extrémně vzácná, ale nezbytná. if (consteval && n < 0) {

auto(x) je dočasná kopie objektu

Snadný způsob, jak získat objekt jako dočasný, jako [12] :

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

x.front() - chyba: v závislosti na kontejneru se tato reference podívá buď na jiný objekt, nebo do prázdné paměti.

Níže uvedený kód je správný, ale auditor může být v pokušení chybně odstranit proměnnou . a

auto a = x . přední (); std :: erase ( x.begin ( ), x. end ( ) , a ) ;

V programování šablon může být obtížné získat tento typ:

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

Název byl vynechán ze dvou důvodů: prvalue je vysoce technický koncept a nevhodné chování pro pole (ukáže ukazatel). prvalue_cast

Operace vícerozměrného indexování (hranaté závorky)

Stávající metody [13] :

pole ( 1 , 2 , 3 , 4 , 5 ) = 42 ; // vypadá hrozně pole [{ 1 , 2 , 3 , 4 , 5 }] = 42 ; // velmi nesrozumitelné a nepříjemné psát pole [ 1 ][ 2 ][ 3 ][ 4 ][ 5 ] = 42 ; // trochu lepší, ale pod kapotou to prostě leze

Zatím pouze pro vlastní typy [14] .

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

Různé knihovny implementují chybějící syntaxi různými způsoby, ale v žádném případě to není kompatibilní se syntaxí standardních polí a ztěžuje automatické hledání chyb a vkládání (nasazení funkce přímo do volajícího kódu).

Předmětem diskuse zůstává: je to nutné pro standardní pole; zda zmírnit požadavky a umožnit to mimo třídu. operator[]

Toto-možnosti

Jedna z vlastností C++ - const-correctness - vede k duplikaci kódu nebo zápisu metod delegování. Je navrženo řešení pomocí šablon [15]

///// WAS ///// class TextBlock { veřejnost : char const & operator []( size_t position ) const { // ... return text [ pozice ]; } znak a operátor []( pozice size_t ) { return const_cast < char &> ( static_cast < TextBlock const &> ( toto )[ pozice ] ); } // ... }; ///// STÁT SE ///// class TextBlock { veřejnost : šablona < typenameSelf > _ auto & operator []( this Self && self , size_t position ) { // ... return self . text [ pozice ]; } // ... };

Metody rozšíření zatím nejsou nabízeny, ale v budoucnu budou možné.

Snížené požadavky na constexpr

Seznam odpustků je dlouhý a souvisí se dvěma věcmi:

  • Nyní constexpr znamená, že při kompilaci je možná alespoň jedna cesta provedení.
  • Knihovny vždy zaostávají za jazykem.

Nyní je tedy možné napsat funkci constexpr, kterou lze bez sady argumentů provést při kompilaci [16] .

Ve funkcích constexpr jsou také povoleny goto , proměnné neliterálních typů, statické/vnitrovláknové proměnné. Pokud je některý z těchto řádků předán během kompilace, funkce je vyhodnocena při provádění. zvýšen na 202103L [17] . __cpp_constexpr

Statický operátor()

Odebere jednu strojovou instrukci, pokud třída nemá žádná data a vkládání selže [18] . Například v samovyvažovacím stromu s nestandardním pořadím (bylo v C++03 ) a heterogenním vyhledávání ( C++14 ) je možný následující kód:

struct CustomCompare { pomocí is_transparent = int ; // heterogenní hledání statický bool operátor () ( std :: string_view a , std :: string_view b ) // byl const, stal se statickým { return someCustomLess ( a , b ); } }; std :: set < std :: string , CustomCompare > things ;

Kódování znaků

Povolené znaky v identifikátorech

Znaky ze sad Unicode XID_Start (start) a XID_Continue (ostatní) jsou nyní povoleny v identifikátorech .

  • Jsou povolena písmena a číslice z různých abeced, včetně čínských znaků , klínového písma a latinsko-arabských matematických písmen, z nichž mnohé jsou znaky podobné písmenům.
  • Znaky typu "písmeno/modifikátor" jsou povoleny - 02C6 ˆ "modifier-cap" je povoleno a 02DA ˚ "upper circle" je typu "znak/modifikátor" a je zakázáno.
  • Kombinování značek je povoleno, včetně selektorů stylu.
  • Emoji , neabecední znaky ze strojírenství a matematiky, formátovací znaky (neviditelné znaky odpovědné za zpracování textu, včetně ZWJ a ZWNJ) jsou zakázány .

Identifikátor musí být normalizován podle algoritmu „kanonického složení“ (NFC, rozložit monolitické znaky na komponenty a znovu sestavit). Pokud ne, program je nesprávný.

Tato změna pouze činí podporu Unicode konzistentnější, ale nijak neřeší problémy s útoky prostřednictvím zdánlivě identických řetězců [19] . Metody předávání takových znaků linkeru závisí na implementaci.

Víceznakové a nezakódované literály wchar_t nejsou povoleny

Různé kompilátory fungovaly odlišně na (facepalm emoji ) na dvoubajtovém wchar_t (Windows), . Obojí je nyní zakázáno [20] . L'\U0001F926'L'ab'

Víceznakové char literály stále fungují, jsou typu int. Kolik znaků je povoleno a jak budou shromážděny do jednoho čísla, je určeno implementací.

Pojmy "kódování překladu", "kódování výkonu"

Je legální, že jeden může být odlišný od druhého [21] a  je jednotkou širokého, implementačně specifického kódování výkonu [22] . wchar_t

UTF-8 jako multiplatformní překladové kódování musí být bezpodmínečně podporováno všemi kompilátory [23] . Značka pořadí bajtů je ignorována, pokud není v konfliktu s příznaky kompilátoru. Pokud je soubor rozpoznán jako UTF-8, neměl by obsahovat nesprávné kombinace kódů – mohou však existovat správné kombinace odpovídající znakům, které ještě neexistují.

Číselné hodnoty znakových literálů v preprocesoru odpovídají kódování provádění

Dříve to bylo až na implementaci, ale ukázalo se, že hlavním účelem této funkce je určit kódování provádění [24] . Například kód z SQLite :

/* Zkontrolujte, zda stroj používá EBCDIC. (Ano, věřte tomu nebo ne, stále existují stroje používající EBCDIC.) */ #if 'A' == '\301' # definovat SQLITE_EBCDIC 1 #else # definovat SQLITE_ASCII 1 #endif

Všechny hlavní kompilátory skutečně fungují tímto způsobem.

Je opět povoleno inicializovat pole char a unsigned char pomocí literálu UTF-8

Všechny tři řádky jsou přerušeny v C++20, práce opět v C++23 [25] .

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

Jak se ukázalo, takové přerušení zkomplikovalo funkce constexpru a narušilo kompatibilitu s C.

Nové screencapy

"\u{1F926}"pro bod v kódu Unicode, pro osmičkovou a pro šestnáctkovou [26] . "\o{123}""\x{AB}"

Prolomení takových štítů ( ) je zakázáno. "\x{4" "2}"

"\N{LATIN CAPITAL LETTER A WITH MACRON}"umožňuje odkazovat na symbol jeho názvem unicode [27] .

Redakční změny

  • Zřetězení zpětného lomítka nyní povoluje mezery za zpětným lomítkem [28] . Takto fungovaly GCC, Clang a ICC - a MSVC zanechalo mezeru.
  • Překladač nesmí přeskupovat pole jednoho objektu, pokud mají nenulovou délku a různá přístupová práva [29] . Takto jednali MSVC, GCC, Clang.
  • Zřetězení řetězců s konfliktními předponami kódování jako . Z hlavních kompilátorů to podporuje pouze SDCC  - přebírá první z prefixů [30] .L"" u""
  • Legalizovaná směrnice #warningpodporovaná všemi [31] .
  • Zjednodušená implicitní pravidla přesunu při návratu z funkce [32] .
  • Refaktorované rozšířené celočíselné typy specifické pro dodavatele [33] .
  • Vyjasněn stav hlavičkových souborů C: jsou nyní pro zpětnou kompatibilitu. Soubor, který nesmí být současně platným souborem C, je nesmí obsahovat [34] .

Harmonizace s C

  • Štítek bez operátoru povolen: [35] .{ goto a; ++x; a: }
  • Podpora . Neexistuje žádný analog [36] .<stdatomic.h><cstdatomic>
  • Je opět povoleno inicializovat pole char a unsigned char pomocí literálu UTF-8 (popsáno výše).

Knihovna

Drobné změny

  • exchangeobdržel podmíněný noexcept - pokud je objekt vytvořen tahem a přiřazen kopií bez vyvolání výjimek [37] .
  • Heterogenní a v asociativních nádobách [38] . Například klíč úložiště je a přístupový klíč je .extracterasestringstring_view
  • string[_view].contains - často potřebujete zkontrolovat přítomnost podřetězce, aniž byste zjistili, kde je shoda [39] .
  • Nová funkce , která plněji využívá vlastnosti mechanismu alokace paměti [40] . Postupně do něj budou migrovat kontejnery s proměnnou velikostí.Allocator.allocate_at_least
  • Rodina konstant  – například pro sledování migrace knihovny ze staré do nové [41] .is_scoped_enumenumenum class
  • Funkce pro převod , která je svým názvem srozumitelnější a méně náchylná k chybám [42] .to_underlyingenum int
  • Funkce v záhlaví pro změnu pořadí bajtů v číslech [43] .byteswap<bit>
  • iostream nyní může tisknout nestálé ukazatele, stejně jako normální ukazatele [44] .

std::move_only_function

std::functionse stal jednou z "nejtěžších" částí knihovny STL. Zbavením se několika vlastností - nelze kopírovat, chybějící pole a  - můžete získat mnohem lehčí objekt [45] . A tento objekt samozřejmě umí pracovat s nekopírovatelnými háčky. targettarget_type

Monad operace na std::volitelné

Monáda  je standardní funkcí funkčních jazyků pro provádění sekvence akcí.

V matematice se posloupnost funkcí zapisuje jako , což není vždy vhodné - v programování něco jako . x.f().g().h()

std::optional  je poměrně jednoduchý wrapper, jehož smyslem je uložit objekt nebo nic. Kontroly „nic“ zabírají velkou část práce s volitelným – ale co když na něm v procesu transformace není žádná kočka? Ale co když není místo, kam nakreslit mašli? [46]

std :: volitelné < obrázek > get_cute_cat ( const image & img ) { return crop_to_cat ( img ) // obrázek → volitelné; [nullopt] na obrázku není žádná kočka . and_then ( add_bow_tie ) // obrázek → volitelné; [nullopt] nikde přidat luk . and_then ( make_eyes_sparkle ) // obrázek → volitelné; [nullopt] nevidí oči . transform ( make_smaller ) // obrázek → obrázek . transformovat ( add_rainbow ); // obrázek → obrázek }

string::resize_and_overwrite

Používá se pro extrémní optimalizaci na křižovatce řetězců a nízkoúrovňových API:

int komprimovat ( void * out , size_t * out_size , const void * in , size_t in_size ); std :: string CompressWrapper ( std :: string_view input ) { std :: řetězec komprimovaný ; komprimovaný . resize_and_overwrite ( input . size (), [ input ]( char * buf , std :: size_t n ) noexcept { std :: velikost_t komprimovaná_velikost = n ; auto is_ok = komprimovat ( buf , & komprimovaná_velikost , vstupní . data (), vstupní . velikost ()); tvrdit ( is_ok ); return komprimovaná_velikost ; }); návrat komprimovaný ; }

Nabízí se otázka: co bylo optimalizováno ve srovnání s těmito dvěma ? [13] Faktem je, že náklady na alokaci paměti příliš nezávisí na délce vyrovnávací paměti a ve většině případů bude do vyrovnávací paměti alokováno mnohem více paměti, než je skutečně potřeba pro komprimovaný řetězec. Nová funkce neinicializuje vyrovnávací paměť a vynulování velmi dlouhé části paměti - . resizememset( compressed.data(), compressed.size(), '\0')

spanstream - náhrada za zakázané v C++98 strstream

Existoval strstream - datový tok běžící na poli omezené délky. Zakázán v C++98, byl navržen další podobný mechanismus.

char output [ 30 ]{}; ospanstream os { span < char > { output }}; os << 10 << 20 << 30 ; auto const sp = os . rozpětí (); ASSERT_EQUAL ( 6 , sp . velikost ()); ASSERT_EQUAL ( "102030" , std :: řetězec ( sp . data (), sp . velikost ())); ASSERT_EQUAL ( static_cast < void *> ( výstup ), sp . data ()); // žádné kopírování dat ASSERT_EQUAL ( "102030" , výstup ); // zaručeně ukončeno null

tisk

Zpočátku to bylo:std::cout << std::format("Hello, {}! You have {} mails", username, email_count);

To…

  • Prodlužuje binární kód - streamy jsou ze své podstaty těžké.
  • Žádná podpora Unicode.
  • Vypadá to ošklivě.

K dispozici je lehčí [47] . std::print("Привет, {}! У вас {} писем", username, email_count);

Volitelné zlomkové typy

název Kousky mantisy bitové pořadí Poznámka
float16_t 10 + implicitní 1 5 Vyhovuje IEEE binary16
bfloat16_t 7 + implicitní 1 osm Horní dva bajty IEEE binary32 (≈float), používané v knihovnách AI, odtud název brain float
float32_t 23 + implicitní 1 osm Vyhovuje IEEE binárním32, většině plovoucích implementací
float64_t 52 + implicitní 1 jedenáct Vyhovuje IEEE binary64, většina implementací double
float128_t 112 + implicitní 1 patnáct Vyhovuje IEEE binary128

Matematické funkce musí mít obaly pro všechny podporované typy - zatímco skutečný výpočet lze provést ve více či méně přesném typu [48] .

Poznámky

  1. Zdroj . Získáno 8. srpna 2022. Archivováno z originálu dne 18. července 2022.
  2. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2327r1.pdf
  3. Zdroj . Získáno 20. července 2022. Archivováno z originálu dne 10. června 2022.
  4. P2360R0: Rozšiřte příkaz init tak, aby umožňoval deklaraci aliasu
  5. Vydání CWG 2397
  6. P1102R2: Pryč s ()! . Získáno 9. srpna 2022. Archivováno z originálu dne 9. srpna 2022.
  7. Zdroj . Získáno 27. července 2022. Archivováno z originálu dne 24. května 2022.
  8. Zúžení kontextových konverzí na bool . Získáno 27. července 2022. Archivováno z originálu dne 27. července 2022.
  9. Změnit rozsah lambda trailing-return-type . Získáno 27. července 2022. Archivováno z originálu dne 27. července 2022.
  10. Zdroj . Získáno 27. července 2022. Archivováno z originálu dne 22. srpna 2022.
  11. Zdroj . Získáno 1. srpna 2022. Archivováno z originálu dne 30. července 2022.
  12. 1 2 `jestliže consteval` . Získáno 20. července 2022. Archivováno z originálu dne 20. července 2022.
  13. 1 2 C++23 - funkce zmrazení zavřít / Sudo Null IT News Získáno 28. července 2022. Archivováno z originálu dne 14. května 2022.
  14. Zdroj . Získáno 20. července 2022. Archivováno z originálu dne 24. května 2022.
  15. Odvození tohoto . Získáno 27. července 2022. Archivováno z originálu dne 12. července 2022.
  16. Uvolnění některých constexpr omezení . Získáno 29. července 2022. Archivováno z originálu dne 25. července 2022.
  17. Nedoslovné proměnné (a štítky a gotos) ve funkcích constexpr . Získáno 20. července 2022. Archivováno z originálu dne 24. května 2022.
  18. statický operátor() . Získáno 29. července 2022. Archivováno z originálu dne 29. července 2022.
  19. Syntaxe identifikátoru C++ využívající standard Unicode, příloha 31 . Získáno 27. července 2022. Archivováno z originálu dne 12. července 2022.
  20. Zdroj . Získáno 27. července 2022. Archivováno z originálu dne 27. července 2022.
  21. P2314R3: Znakové sady a kódování . Získáno 27. července 2022. Archivováno z originálu dne 24. května 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. Zdroj . Získáno 27. července 2022. Archivováno z originálu dne 24. května 2022.
  25. D2513R3: Oprava kompatibility a přenositelnosti char8_t
  26. Zdroj . Získáno 29. července 2022. Archivováno z originálu dne 24. května 2022.
  27. Pojmenované univerzální znaky escape . Získáno 29. července 2022. Archivováno z originálu dne 29. července 2022.
  28. Zdroj . Získáno 27. července 2022. Archivováno z originálu dne 24. května 2022.
  29. Zdroj . Získáno 27. července 2022. Archivováno z originálu dne 24. května 2022.
  30. P2201R1: Smíšené řetězcové doslovné zřetězení . Získáno 27. července 2022. Archivováno z originálu dne 27. července 2022.
  31. Zdroj . Získáno 27. července 2022. Archivováno z originálu dne 30. července 2022.
  32. P2266R3: Jednodušší implicitní tah . Získáno 1. srpna 2022. Archivováno z originálu dne 24. května 2022.
  33. Vyčištění typů celočíselných tříd
  34. Vyjasnění stavu „hlaviček C“
  35. Zdroj . Získáno 29. července 2022. Archivováno z originálu dne 17. června 2022.
  36. P0943R6: Podpora atomů C v C . Získáno 8. srpna 2022. Archivováno z originálu dne 8. srpna 2022.
  37. P2401R0: Přidejte podmíněnou specifikaci noexcept do std::exchange . Získáno 28. července 2022. Archivováno z originálu dne 28. července 2022.
  38. P2077R3: Heterogenní přetížení při výmazu pro asociativní kontejnery . Získáno 29. července 2022. Archivováno z originálu dne 24. května 2022.
  39. řetězec obsahuje funkci . Získáno 8. srpna 2022. Archivováno z originálu dne 8. srpna 2022.
  40. P0401R6: Poskytování zpětné vazby velikosti v rozhraní alokátoru . Získáno 8. srpna 2022. Archivováno z originálu dne 20. července 2022.
  41. Zdroj . Získáno 8. srpna 2022. Archivováno z originálu dne 24. května 2022.
  42. P1682R3: std::to_underlying pro výčty . Získáno 8. srpna 2022. Archivováno z originálu dne 8. srpna 2022.
  43. P1272R4: Byteswapping pro zábavu&nuf . Získáno 8. srpna 2022. Archivováno z originálu dne 8. srpna 2022.
  44. P1147R1: Tisk „volatilních“ ukazatelů
  45. P0288R9: move_only_function . Získáno 20. července 2022. Archivováno z originálu dne 20. července 2022.
  46. p0798R6: Monadické operace pro std::volitelné . Získáno 20. července 2022. Archivováno z originálu dne 20. července 2022.
  47. P2093R14: Formátovaný výstup . Získáno 29. července 2022. Archivováno z originálu dne 24. července 2022.
  48. P1467R9: Rozšířené typy s plovoucí desetinnou čárkou a standardní názvy . Získáno 29. července 2022. Archivováno z originálu dne 29. července 2022.