Il comitato ISO per la standardizzazione del linguaggio C++ ha completato e approvato la versione finale della specifica che costituirà lo standard internazionale "C++26". Le funzionalità presentate nella specifica sono già parzialmente supportate nei compilatori GCC, Clang e Microsoft Visual C++. Le librerie standard che supportano C++26 sono implementate nel progetto Boost.
Nei prossimi due mesi, la specifica approvata sarà in fase di preparazione del documento per la pubblicazione, durante la quale verrà eseguito il lavoro di correzione editoriale per errori ortografici e refusi. All'inizio di novembre, la versione finale del documento sarà inviata all'ISO per la pubblicazione con il nome formale ISO/IEC 14882:2026.
Principali caratteristiche di C++26:
- Sono stati implementati gli elementi di programmazione contrattuale (Contracts), che consentono di definire specifiche formali delle interfacce attraverso tre nuovi operatori: pre (precondizione), post (postcondizione) e contract_assert (verifica dell'affermazione). L'operatore «pre» definisce le condizioni preliminari che devono essere soddisfatte prima della chiamata (verifica degli input); «post» — le condizioni che devono essere rispettate dopo l'esecuzione (requisiti per l'output); contract_assert — condizioni di generazione delle eccezioni. Questa funzionalità sarà disponibile in GCC 16. int f(const int x) pre (x != 1) // requisiti per gli input post (r : r == x && r != 2) // requisiti per il risultato; r — valore di output { contract_assert (x != 3); return x; }
- È stata aggiunta la supporto per la riflessione (Reflection), che consente di monitorare e modificare gli elementi del programma durante la fase di compilazione. Sono stati aggiunti i nuovi operatori «^^» per ottenere metainformazioni sulla costruzione grammaticale e «[:…:]» per eseguire la trasformazione inversa. Per la trasformazione e l'elaborazione delle informazioni ottenute durante l'ispezione, è stata proposta la libreria std::meta ed è disponibile la possibilità di calcoli con le costanti. Il supporto per la riflessione sarà incluso in GCC 16. 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’ e ‘j’ hanno valori diversi. static_assert(constant_of(^^i) == constant_of(^^j)); // ‘i’ e ‘j’ sono identici static_assert(^^i != std::meta::reflect_constant(42)); // differente dal valore 42
- È stato aggiunto l'operatore «template for» per iterare su elementi come pacchetti di parametri, oggetti simili a tuple e risultati di riflessione (meto-oggetti) durante la fase di compilazione in stile ciclo tradizionale. Durante l'esecuzione di «template for», il corpo del ciclo viene espanso per ogni elemento e ogni iterazione viene trattata in un'area di visibilità separata, dove la variabile che cambia nel ciclo è una costante. Nel contesto della riflessione, «template for» può essere utilizzato per scorrere le proprietà di classi o enumerazioni. Questa funzionalità sarà disponibile in GCC 16. void f() { template for (constexpr int I : std::array{1, 2, 3}) { static_assert(I < 4); } } sarà espanso in: 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); } } }
- È stato aggiunto il framework std::execution per l'esecuzione asincrona e parallela del codice. Sono forniti oggetti scheduler, che definiscono il pianificatore di esecuzione (thread, pool di thread, GPU, event loop), sender, che definisce il lavoro da eseguire, e receiver — il gestore del risultato. 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();
- È stata aggiunta la libreria std::simd per parallelizzare l'esecuzione di operazioni sui dati utilizzando set di istruzioni SIMD, come AVX-512 e NEON, con il sistema di tipi standard C++. 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;
- È stata proposta un'implementazione di un vettore (array) di dimensioni variabili std::inplace_vector, allocato nello stack, la cui dimensione è determinata al momento della compilazione. L'API è simile a quella di std::vector, ma gli elementi dell'array sono memorizzati non nella "heap", ma all'interno dell'oggetto. inplace_vector a(10); inplace_vector b(std::move(a)); assert(a.size() == 10);
- È stata aggiunta la direttiva «#embed», destinata all'inserimento nel codice di risorse binarie. const unsigned char icon_display_data[] = { #embed «art.png» };
- È stata aggiunta la supporto per la generazione e la gestione delle eccezioni durante la fase di compilazione in caso di errori nel contesto di constexpr. constexpr std::optional 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(input); if (!correct) { throw incorrect_date{input}; } return build_date(year, month, day); }
- È stata implementata la struttura dati std::hive per lo stoccaggio non ordinato dei dati e per il riutilizzo della memoria liberatasi dopo la rimozione di elementi. La struttura è ottimizzata per carichi con elevata intensità di aggiunta e rimozione di elementi in ordine arbitrario. A differenza degli array, la rimozione di un elemento in std::hive non causa lo spostamento di altri elementi, ma comporta la marcatura dell'elemento rimosso come vuoto, con successivo riempimento della posizione liberata all'aggiunta di un nuovo elemento.
- È stata aggiunta la libreria std::linalg con API per l'algebra lineare, basata su BLAS.
- Aggiunta la supporto per il meccanismo di sincronizzazione Hazard pointer, che consente di prevenire il rilascio della memoria degli oggetti senza utilizzare blocchi, mentre si continua a lavorare su di essi in altri thread. Quando un oggetto viene eliminato, viene semplicemente contrassegnato come eliminato, ma la memoria occupata dall'oggetto viene liberata solo quando tutti i thread rimuovono l'indirizzatore hazard impostato durante il lavoro con l'oggetto.
- Aggiunta la supporto per il meccanismo di sincronizzazione RCU (Read-Copy Update) — durante le operazioni di scrittura viene creato un nuovo istanza dell'oggetto, mentre le operazioni di lettura non vengono bloccate e continuano a lavorare con il vecchio istanza. Dopo il completamento della modifica, il nuovo istanza diventa attivo e le nuove operazioni di lettura vengono eseguite su di esso, mentre il vecchio istanza viene eliminato dopo che i thread che lo leggevano hanno terminato.
- Effettuate modifiche per rafforzare la sicurezza della libreria standard, come controlli sui valori ammissibili e sui limiti di buffer. Ad esempio, nell'accesso all'elemento «constexpr reference operator[](size_type idx) const;» viene aggiunta una verifica della condizione «idx < size()».
- È stata introdotta la possibilità di utilizzare la parola chiave «constexpr» con la variante dell'operatore «new» (placement new) per posizionare un oggetto nella memoria precedentemente allocata durante la compilazione.
- È stata aggiunta la supporto per il binding strutturato (structured binding) nel contesto di «constexpr», ovvero i riferimenti a espressioni costanti possono ora essere costanti di espressione. Il supporto è stato implementato per array e strutture semplici. constexpr int arr[] = {1, 2}; constexpr auto [x, y] = arr;
- Nelle strutture di binding è stata aggiunta la possibilità di utilizzare la sintassi «…» per specificare pacchetti (pack), che raccolgono il numero rimanente di elementi dalla sequenza assegnata. auto [x,y,z] = f(); // nelle variabili x, y, z verranno memorizzati i tre elementi restituiti da f(). auto […xs] = f(); // nel pacchetto xs verranno memorizzati tutti gli elementi restituiti da f(). auto [x, …rest] = f(); // In x verrà memorizzato il primo elemento e in rest i restanti. auto [x, y, …rest] = f(); // In x verrà memorizzato il primo elemento, in y il secondo e in rest il terzo. auto [x, …rest, z] = f(); // in x il primo, in rest il secondo, in z il terzo.
- È stata aggiunta la supporto per la «trivial relocation» di tipi (Trivial Relocatability), consentendo di ottimizzare gli spostamenti di oggetti di un dato tipo attraverso la loro clonazione in memoria senza invocare costruttori o distruttori. Per le classi sono state implementate le proprietà memberwise_trivially_relocatable e memberwise_replaceable, e per il movimento a basso livello di uno o più oggetti sono state aggiunte le funzioni trivially_relocate_at e trivially_relocate.
- È stata implementata la possibilità di collegare la funzione main() a un modulo globale e definire la funzione main() all'interno di moduli nominati.
- È stato aggiunto l'operatore variabile «friend» («friend Ts…»).
- Sono stati implementati attributi per i binding strutturati;
- È stata aggiunta la sintassi ‘= delete(«motivo»)’.
- Il set di caratteri di base ora include «@», «$» e «`».
- È stata fornita la possibilità di applicare il binding strutturato (structured binding) come condizione negli operatori if e switch.
- È stata aggiunta la possibilità di utilizzare più variabili di riempimento con nome «_» in un singolo ambito, ad esempio, ora le seguenti costruzioni sono corrette: struct S { int _, _; }; void func() { int _, _; } void other() { int _; // precedentemente emesso un avviso in modalità -Wunused }
- È stata fornita la possibilità di utilizzare letterali di stringa in un contesto in cui non sono utilizzati per inizializzare un array di caratteri e non vengono inclusi nel codice risultante, ma sono impiegati solo durante la compilazione per messaggi diagnostici e pre-processing, ad esempio, come parametri per direttive e attributi _Pragma, asm, extern, static_assert, [[deprecated]] e [[nodiscard]].
- Sono state aggiunte funzioni integrate: «__builtin_is_within_lifetime» per controllare l'attività di un'alternativa nelle unioni (union) e «__builtin_is_virtual_base_of» per verificare se una classe base è virtuale.
- Realizzati cicli triviati infiniti senza comportamento indefinito.
- È stato fornito un output di errore quando si elimina un puntatore a un tipo incompleto.
- È stato dichiarato obsoleto il syntax per definire parametri variabili con i puntini di sospensione senza una virgola precedente (ad esempio, quando si dichiara «void e(int…)» invece di «void e(int, …)»).
- È vietato l'uso di macro per la dichiarazione di moduli.
- Spostato nella categoria obsoleta l'esecuzione di conversioni implicite di valori enumerati in calcoli aritmetici. int main() { enum E1 { e }; enum E2 { f }; bool b = e <= 3.7; // obsoleto int k = f - e; // obsoleto int x = +f - e; // OK }
- Interrotta la supporto per il confronto diretto degli array. int arr1[5]; int arr2[5]; bool same = arr1 == arr2;
- Dichiarato obsoleto il template class is_trivial.
Fonte: opennet.ru
