Az ISO C++ szabványosító bizottsága véglegesítette a C++26 nemzetközi szabványhoz tartozó specifikációt. A specifikációban szereplő lehetőségeket részben már támogatják a GCC, Clang és Microsoft Visual C++ fordítók. A C++26 szabványos könyvtárakat a Boost projekt keretein belül valósították meg.
A következő két hónapban a jóváhagyott specifikáció a dokumentum publikálásra való előkészítése alatt áll, amely során a helyesírási hibák és elírások szerkesztésére kerül sor. November elején a dokumentum végleges változatát az ISO-nak küldik el, formális neve ISO/IEC 14882:2026 lesz.
A C++26 főbb jellemzői:
- Megvalósították a szerzői szerződéses programozás (Contracts) elemeit, amelyek lehetővé teszik a felületek formális specifikációinak meghatározását három új operátor segítségével: pre (előfeltétel), post (utófeltétel) és contract_assert (állítás-ellenőrzés). A pre operátor azokat a feltételeket határozza meg, amelyeket a hívás előtt kell teljesíteni (belső adatok ellenőrzése); a post azokat a feltételeket, amelyeket a végrehajtás után be kell tartani (kimeneti adatok követelményei); contract_assert a kivétel előidézésének feltételei. Ez a lehetőség a GCC 16-ban jelenik meg. int f(const int x) pre (x != 1) // belső adatok követelményei post (r : r == x && r != 2) // a kimenetre vonatkozó követelmények; r — a kimeneti érték { contract_assert (x != 3); return x; }
- Hozzáadódott a reflexió (Reflection) támogatása, amely lehetővé teszi a program elemeinek nyomon követését és módosítását a fordítási fázisban. Új operátorokat vezettek be: „^^” a nyelvtani szerkezet meta-információjának lekérdezésére, valamint „[:…:]” a visszafelé történő átalakításhoz. Az ellenőrzés során nyert információk átalakítására és feldolgozására a std::meta könyvtár került bevezetésre, amely olyan lehetőségeket kínál, mint a konstansokkal való számítás. A reflexió támogatás hamarosan megjelenik a GCC 16-ban. constexpr int i = 42, j = 42; constexpr std::meta::info r = ^^i, s = ^^i; static_assert(r == r && r == s); static_assert( ^^i != ^^j); // ‘i’ és ‘j’ eltérő értékeket képviselnek. static_assert(constant_of( ^^i) == constant_of( ^^j)); // ‘i’ és ‘j’ azonosak static_assert( ^^i != std::meta::reflect_constant(42)); // eltér az 42 értéktől
- Hozzáadva a "template for" operátor, amely lehetővé teszi a paramétercsomagok, tuple-szerű objektumok és a reflektáló eredmények (metaobjektumok) elemeinek bejárását a fordítási időben, a szokásos ciklus stílusában. A "template for" végrehajtása során a ciklus törzse minden elem esetén kibővítésre kerül, és minden iteráció egy külön névtérben zajlik, ahol a ciklusban változóként szereplő változó állandó. A reflexió kontextusában a "template for" alkalmazható a osztályok vagy felsorolások tulajdonságainak bejárására. A lehetőség a GCC 16-ban fog megjelenni. void f() { template for (constexpr int I : std::array{1, 2, 3}) { static_assert(I < 4); } } kibővítve: void f() { { constexpr auto&& __range = std::array{1, 2, 3}; constexpr auto __begin = __range.begin(); constexpr auto __expansion_size = __range.end() - __begin; \/\/ 3 { constexpr int I = *(__begin + 0); static_assert(I < 4); } { constexpr int I = *(__begin + 1); static_assert(I < 4); } { constexpr int I = *(__begin + 2); static_assert(I < 4); } } }
- Hozzáadva az std::execution keretrendszer az aszinkron és párhuzamos kódvégrehajtáshoz. Scheduler objektumok biztosítják a munkák végrehajtásának ütemezőjét (szál, szálmedence, GPU, eseményhurok), a sender a végrehajtandó feladatot, és a receiver az eredmény kezelője. using namespace std::execution; scheduler auto sch = thread_pool.scheduler(); sender auto begin = schedule(sch); sender auto hi = then(begin, []{ std::cout << "Hello world! Have an int."; return 13; }); sender auto add_42 = then(hi, [](int arg) { return arg + 42; }); auto [i] = this_thread::sync_wait(add_42).value();
- Hozzáadva az std::simd könyvtár a SIMD utasításkészletek, mint az AVX-512 és NEON, adatainak párhuzamos végrehajtásához a C++ szabványos típusait használva. std::simd a = {1.0f, 2.0f, 3.0f, 4.0f}; std::simd b = {5.0f, 6.0f, 7.0f, 8.0f}; std::simd result = a + b;
- Javasolt megvalósítása a változó méretű vektornak (tömb) std::inplace_vector, amely a veremben foglal helyet, és mérete a fordítási időben kerül meghatározásra. Az API közel áll az std::vector-hoz, de a tömb elemei nem a "heapben", hanem az objektum belsejében tárolódnak. inplace_vector a(10); inplace_vector b(std::move(a)); assert(a.size() == 10);
- Hozzáadva a "#embed" direktíva, amely bináris erőforrások beágyazására szolgál a kódba. const unsigned char icon_display_data[] = { #embed "art.png" };
- Hozzáadtuk a kivételkezelés generálásának és feldolgozásának támogatását a fordítási szakaszban, amikor hibák lépnek fel a constexpr kontextusában. constexpr std::optional<unsigned> checked_divide(unsigned n, unsigned d) { try { return divide(n, d); } catch (…) { return std::nullopt; } } constexpr date parse_date(std::string_view input) { auto [correct, year, month, day] = ctre::match<«([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})»>(input); if (!correct) { throw incorrect_date{input}; } return build_date(year, month, day); }
- Megvalósítottuk a std::hive adatstruktúrát az adatok rendezetlen tárolására és a törölt elemek után felszabadult memória újrafelhasználására. A struktúra optimalizálva van olyan terhelésekhez, ahol elemeket nagy intenzitással adnak hozzá és törölnek véletlenszerű sorrendben. Ellentétben a tömbökkel, a std::hive-ban egy elem törlése nem okoz más elemek elmozdulását, hanem a törölt elemet üresnek jelöli, és a felszabadult helyet egy új elem hozzáadásakor tölti be.
- Hozzáadtuk az std::linalg könyvtárat a BLAS-ra épülő lineáris algebrai API-val.
- Hozzáadtuk a Hazard pointer szinkronizációs mechanizmus támogatását, amely lehetővé teszi a memóriaszivárgás megelőzését a zárolások beállítása nélkül azoknál az objektumoknál, amelyekkel más szálak továbbra is dolgoznak. Az objektum törlésekor csak töröltnek jelölik, de a megszűnt objektum által elfoglalt memória csak akkor szabadul fel, amikor minden szál eltávolítja a hazard mutatót, amelyet az objektummal való munka során állítottak be.
- Hozzáadtuk az RCU (Read-Copy Update) szinkronizációs mechanizmus támogatását – írási műveletek során új objektum példányt hoznak létre, míg az olvasási műveletek nem blokkolják, hanem továbbra is az előző példánnyal dolgoznak. A módosítás befejezése után az új példány aktívvá válik, és az új olvasási műveleteket már ezzel hajtják végre, míg a régi példányt az olvasó szálak befejezése után törlik.
- Változtatásokat hajtottunk végre a szabványos könyvtár biztonságának megerősítése érdekében, mint például a megengedett értékek és a határok túllépésének ellenőrzése. Például a «constexpr reference operator[](size_type idx) const;» elemhez való hozzáféréskor feltételes ellenőrzés történik «idx < size()».
- Lehetővé vált a «constexpr» kulcsszó használata a «new» operátor (placement new) változataival, hogy egy objektumot előre lefoglalt memóriában helyezzenek el a fordítási idő alatt.
- Bevezetésre került a strukturált kötések (structured binding) támogatása a "constexpr" kontextusában, azaz a konstans kifejezések referenciái most maguk is lehetnek konstans kifejezések. A támogatás tömbök és egyszerű struktúrák esetében valósult meg. constexpr int arr[] = {1, 2}; constexpr auto [x, y] = arr;
- A strukturált kötésekhez hozzáadódott a "..." szintaxis használatának lehetősége, amely a csomagok (pack) megadására szolgál, amelyek a hozzárendelt sorozatból a hátralévő elemeket ragadják meg. auto [x,y,z] = f(); // a x, y, z változókba három elemet tárolunk el, amelyet f() ad vissza. auto […xs] = f(); // a csomagba xs minden, f() által visszaadott elem el lesz tárolva. auto [x, …rest] = f(); // x-be az első elem, míg a rest-be a többi kerül. auto [x, y, …rest] = f(); // x-be az első, y-ba a második, a rest-be a harmadik kerül. auto [x, …rest, z] = f(); // x-be az első, a rest-be a második, z-be a harmadik kerül.
- Bevezetésre került a típusok "triviális mozgathatóságának" (Trivial Relocatability) támogatása, amely lehetővé teszi az adott típusú objektumok mozgatását az ő másolásukkal a memóriában, anélkül, hogy konstruktőröket vagy destruktőröket hívnánk meg. Az osztályok számára megvalósult a memberwise_trivially_relocatable és memberwise_replaceable tulajdonság, míg az alacsony szintű áthelyezéshez egy vagy több objektum esetén a trivially_relocate_at és trivially_relocate függvények is hozzáadásra kerültek.
- Megvalósításra került a main() függvény globális modulhoz való csatolásának és a main() függvény névvel ellátott modulokban való meghatározásának támogatása.
- Hozzáadódott a változó arányú "friend" operátor ("friend Ts...").
- Megvalósult a strukturált kötésekhez tartozó attribútumok támogatása;
- Hozzáadódott az ‘= delete("oka")’ szintaxis.
- Az alap karakterkészletbe bekerült a „@”, „$” és „`”.
- Lehetőség nyílt a strukturált kötés (structured binding) alkalmazására az if és switch operátorok ban mint feltétel.
- Lehetőség nyílt több, azonos nevű "_" kitöltő változó egyetlen láthatóságban való használatára, például az alábbi konstrukciók most már helyesek: struct S { int _, _; }; void func() { int _, _; } void other() { int _; // korábban figyelmeztetés jelent meg -Wunused módban }
- Lehetőség nyílt szöveges literálok használatára olyan összefüggésben, ahol azok nem szolgálnak karaktertömb inicializálására és nem kerülnek bele az eredménykódba, csupán a fordítási folyamat során használatosak diagnosztikai üzenetek és előfeldolgozás céljából, például az irányelvek és a _Pragma, asm, extern, static_assert, [[deprecated]] és [[nodiscard]] attribútumait paraméterként alkalmazva.
- Beépített funkciók tárcsázva: «__builtin_is_within_lifetime» az uniókban található alternatíva aktív állapotának ellenőrzésére, és «__builtin_is_virtual_base_of» a virtuális bázisosztályok ellenőrzésére.
- Triviális végtelen ciklusok valósultak meg, amelyek nem generálnak meghatározatlan viselkedést.
- Hibaüzenet kerül kiadásra, ha hiányos típusra mutatók törlésre kerülnek.
- Elavultnak nyilvánították a változó paraméterek definiálásának szintaxisát a precedens nélküli három ponttal (például, amikor «void e(int…)» helyett «void e(int, …)» van megadva).
- Makrók modulok deklarálására vonatkozó használata tilos.
- Elavultává vált, hogy az enumerációs értékek implicit konverzióival aritmetikai műveletekben lehet dolgozni. int main() { enum E1 { e }; enum E2 { f }; bool b = e <= 3.7; // elavult int k = f - e; // elavult int x = +f - e; // OK }
- Megszűnt a közvetlen tömb összehasonlításának támogatása. int arr1[5]; int arr2[5]; bool same = arr1 == arr2;
- Elavultnak nyilvánították az is_trivial sablonosztályt.
Forrás: opennet.ru
