Le comité ISO de normalisation du langage C++ a finalisé et approuvé la version finale de la spécification, qui constitue la norme internationale « C++26 ». Les fonctionnalités présentées dans cette spécification sont déjà partiellement prises en charge par les compilateurs GCC, Clang et Microsoft Visual C++. Les bibliothèques standards supportant C++26 sont mises en œuvre dans le cadre du projet Boost.
Au cours des deux prochains mois, la spécification approuvée sera au stade de préparation du document pour la publication, au cours duquel un travail de révision sera effectué pour corriger les erreurs d'orthographe et les coquilles. Début novembre, la version résultante du document sera envoyée à l'ISO pour publication sous le nom formel ISO/IEC 14882:2026.
Principales caractéristiques de C++26 :
- Les éléments de la programmation par contrat (Contracts) ont été implémentés, permettant de définir des spécifications formelles des interfaces à l'aide de trois nouveaux opérateurs : pre (précondition), post (postcondition) et contract_assert (vérification d'assertion). L'opérateur « pre » définit les conditions préalables qui doivent être remplies avant un appel (vérification des données d'entrée) ; « post » - les conditions qui doivent être respectées après l'exécution (exigences sur les données de sortie) ; contract_assert - les conditions de déclenchement d'exceptions. Cette fonctionnalité apparaîtra dans GCC 16. int f(const int x) pre (x != 1) // exigences sur les données d'entrée post (r : r == x && r != 2) // exigences sur le résultat ; r — valeur du résultat { contract_assert (x != 3); return x; }
- Ajout de la prise en charge de la réflexion (Reflection), permettant de suivre et de modifier les éléments du programme lors de la compilation. De nouveaux opérateurs « ^^ » ont été ajoutés pour obtenir des métadonnées sur la construction grammaticale et « [:…:] » pour effectuer une transformation inverse. Pour la transformation et le traitement des informations obtenues lors de l'inspection, une bibliothèque std::meta a été proposée, avec des fonctionnalités telles que le calcul avec des constantes. La prise en charge de la réflexion sera ajoutée dans 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’ et ‘j’ ont des valeurs différentes. static_assert(constant_of(^^i) == constant_of(^^j)); // ‘i’ et ‘j’ sont identiques static_assert(^^i != std::meta::reflect_constant(42)); // différent de 42
- Un opérateur «template for» a été ajouté pour parcourir des éléments tels que des paquets de paramètres, des objets similaires à des tuples, et des résultats de réflexion (méta-objets), au stade de la compilation dans le style d'une boucle classique. Lors de l'exécution de «template for», le corps de la boucle est développé pour chaque élément et chaque itération est traitée dans une portée distincte, où la variable modifiée dans la boucle est une constante. Dans le contexte de la réflexion, «template for» peut être utilisé pour itérer sur les propriétés des classes ou des énumérations. Cette fonctionnalité apparaîtra dans GCC 16. void f() { template for (constexpr int I : std::array{1, 2, 3}) { static_assert(I < 4); } } sera développé en: 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); } } }
- Un cadre std::execution a été ajouté pour l'exécution asynchrone et parallèle du code. Des objets scheduler sont fournis, définissant le planificateur des travaux (fil, pool de fils, GPU, boucle d'événements), sender, définissant le travail exécuté, et receiver — le gestionnaire de résultats. 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();
- Une bibliothèque std::simd a été ajoutée pour paralléliser l'exécution d'opérations sur les données à l'aide d'ensembles d'instructions SIMD, tels que AVX-512 et NEON, en utilisant le système de types 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;
- Une implémentation d'un vecteur (tableau) de taille variable std::inplace_vector, alloué sur la pile, dont la taille est déterminée au moment de la compilation, a été proposée. L'API est proche de std::vector, mais les éléments du tableau sont stockés non pas dans le «tas», mais à l'intérieur de l'objet. inplace_vector a(10); inplace_vector b(std::move(a)); assert(a.size() == 10);
- Une directive «#embed» a été ajoutée, destinée à intégrer des ressources binaires dans le code. const unsigned char icon_display_data[] = { #embed "art.png" };
- Ajout de la prise en charge de la génération et du traitement des exceptions au moment de la compilation lors d'erreurs dans le contexte 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); }
- Implémentation de la structure de données std::hive pour le stockage non ordonné des données et la réutilisation de la mémoire libérée après la suppression d'éléments. La structure est optimisée pour des charges de travail avec une haute fréquence d'ajout et de suppression d'éléments dans un ordre aléatoire. Contrairement aux tableaux, la suppression d'un élément dans std::hive ne provoque pas de décalage des autres éléments, mais marque l'élément supprimé comme vide, avec un remplissage de la position libérée lors de l'ajout d'un nouvel élément.
- Ajout de la bibliothèque std::linalg avec une API pour l'algèbre linéaire, basée sur BLAS.
- Ajout de la prise en charge du mécanisme de synchronisation Hazard pointer, permettant, sans recours à des verrouillages, d'éviter la libération de la mémoire des objets encore utilisés dans d'autres threads. Lors de la suppression d'un objet, il est seulement marqué comme supprimé, mais la mémoire occupée par l'objet n'est libérée que lorsque tous les threads ont retiré le pointeur de hazard, mis en place lors de l'utilisation de l'objet.
- Ajout de la prise en charge du mécanisme de synchronisation RCU (Read-Copy Update) — lors des opérations d'écriture, un nouvel exemplaire de l'objet est créé, tandis que les opérations de lecture ne sont pas verrouillées, mais continuent à fonctionner avec l'ancien exemplaire. Une fois la modification terminée, le nouvel exemplaire devient actif et les nouvelles opérations de lecture sont effectuées avec lui, tandis que l'ancien exemplaire est supprimé une fois que tous les threads qui le lisent ont terminé.
- Modifications apportées pour renforcer la sécurité de la bibliothèque standard, telles que le contrôle des valeurs autorisées et le dépassement de tampon. Par exemple, lors de l'accès à l'élément «constexpr reference operator[](size_type idx) const;», un contrôle de la condition «idx < size()» est ajouté.
- Possibilité d'utiliser le mot-clé «constexpr» avec une variante de l'opérateur «new» (placement new) pour placer un objet dans une mémoire allouée à l'avance lors de la compilation.
- Ajout de la prise en charge des liaisons structurées (structured binding) dans le contexte « constexpr », c'est-à-dire que les références aux expressions constantes peuvent maintenant elles-mêmes être des expressions constantes. La prise en charge est mise en œuvre pour les tableaux et les structures simples. constexpr int arr[] = {1, 2}; constexpr auto [x, y] = arr;
- La possibilité d'utiliser la syntaxe « ... » pour spécifier des paquets (pack), capturant le reste des éléments de la séquence d'affectation, a été ajoutée aux liaisons structurées. auto [x,y,z] = f(); // les variables x, y, z recevront trois éléments retournés par f(). auto […xs] = f(); // le paquet xs recevra tous les éléments retournés par f(). auto [x, …rest] = f(); // x contiendra le premier élément, tandis que rest contiendra les autres. auto [x, y, …rest] = f(); // x contiendra le premier élément, y le deuxième, et rest le troisième. auto [x, …rest, z] = f(); // x est le premier, rest est le deuxième, z est le troisième.
- Ajout de la prise en charge de la « trivialité de déplacement » des types (Trivial Relocatability), permettant d'optimiser le déplacement des objets d'un type donné par leur clonage en mémoire sans appeler de constructeurs ou de destructeurs. Pour les classes, les propriétés memberwise_trivially_relocatable et memberwise_replaceable ont été mises en œuvre, et pour le déplacement bas niveau d'un ou plusieurs objets, des fonctions trivially_relocate_at et trivially_relocate ont été ajoutées.
- Prise en charge de la liaison de la fonction main() au module global et de la définition de la fonction main() dans des modules nommés.
- Ajout de l'opérateur variadique « friend » (« friend Ts… »).
- Des attributs pour les liaisons structurées ont été mis en œuvre.
- Ajout de la syntaxe ‘= delete(« raison »)’.
- Les symboles « @ », « $ » et « ` » ont été ajoutés à l'ensemble de caractères de base.
- Il est maintenant possible d'appliquer la liaison structurée (structured binding) en tant que condition dans les opérateurs if et switch.
- Ajout de la possibilité d'utiliser plusieurs variables de substitution nommées « _ » dans un même espace de noms, par exemple, les constructions suivantes sont maintenant correctes : struct S { int _, _; }; void func() { int _, _; } void other() { int _; // auparavant, un avertissement était affiché en mode -Wunused }
- Il est désormais possible d'utiliser des littéraux de chaîne dans des contextes où ils ne sont pas utilisés pour initialiser un tableau de caractères et ne sont pas inclus dans le code résultant, mais sont uniquement appliqués lors de la compilation pour des messages de diagnostic et du prétraitement, par exemple, en tant que paramètres de directives et d'attributs _Pragma, asm, extern, static_assert, [[deprecated]] et [[nodiscard]].
- Des fonctions intégrées ont été ajoutées : «__builtin_is_within_lifetime» pour vérifier l'activité d'une alternative dans les unions et «__builtin_is_virtual_base_of» pour vérifier si une classe de base est virtuelle.
- Des boucles infinies triviales ont été mises en œuvre sans comportement indéfini.
- Un message d'erreur est désormais affiché lors de la suppression d'un pointeur vers un type incomplet.
- La syntaxe de définition des paramètres variadiques avec des points de suspension sans virgule préalable (par exemple, en déclarant «void e(int…)» au lieu de «void e(int, …)») est déclarée obsolète.
- L'utilisation de macros pour déclarer des modules est interdite.
- Il est déclaré obsolète d'effectuer des conversions implicites de valeurs énumérées dans des calculs arithmétiques. int main() { enum E1 { e }; enum E2 { f }; bool b = e <= 3.7; // obsolète int k = f - e; // obsolète int x = +f - e; // OK }
- Le support de la comparaison directe des tableaux a été arrêté. int arr1[5]; int arr2[5]; bool same = arr1 == arr2;
- La classe template is_trivial a été déclarée obsolète.
Source : opennet.ru
