À propos de WG21, Brno 2026 (juin)

Je participe à cette rencontre à distance encore une fois (ces dernières années je n'ai pas réussi à mettre de côté les fonds requis pour aller à ces rencontres en personne, malheureusement). La rencontre de cette semaine se tenant à Brno (Tchéquie), le décalage horaire sera violent (les rencontres débutent à 2 h 30 du matin heure de Montréal). Mes dossiers n'ont pas progressé ces derniers mois alors je participerai mais je ne présenterai pas de propositions moi-même. Cette semaine, le centre d'attention est C++ 29.

Je devrais passer ma semaine chez CWG comme à mon habitude. Une proposition assez conséquente, p3891, propose rien de moins qu'une refonte importante de la grammaire du langage, en particulier tout ce qui a trait aux séquences, aux aspects optionnels et aux groupes de type « un parmi ceux-ci ». Ça risque de prendre beaucoup de temps et d'énergie chez CWG.

Tout ce qui suit est anonymisé et simplifié, dans le respect du code de conduite d'ISO en vigueur lors de nos rencontres.

Ce document est incomplet (j'ai manqué de temps). Je compléterai dès que possible.

Pour les « journaux de voyage » d'autres participants, voir :

Jour 0 – 8 juin 2026

(j'ai manqué la plénière; mon réveil a sonné mais n'a pas réussi à me réveiller; j'arrive alors qu'on discute de P2952 – auto& operator=(X&&) = default)

P2952 – auto& operator=(X&&) = default

La proposition est de permettre d'utiliser la déduction de types et =default dans plus de cas que operator<=>(), par exemple operator==() et operator=(). À mon arrivée (vers le milieu de la matinée), on discute des règles pour déduire le type de retour. L'enjeu est que auto doit donner ce qu'on s'attend pour le type (dans l'affectation, une référence sur le type l'opérande de gauche; sur operator==(), on veut bool) et il faut que les règles nous mènent à la bonne décision. On veut aussi que =default soit équivalent à =delete si, par exemple, on implémente l'affectation de copie mais l'une des données membres est incopiable.

P2287 – Designated-initializers for Base Classes

Le but ici est de permettre de remplacer ceci :

[&]{
  B b;
  b.a = 5;
  b.b = 6;
  return b;
}();

... par cela :

B{.a=5, .b=6 }

... dans le cas où B n'a pas de constructeur (on vise manifestement un meilleur support des agrégats). Par exemple :

struct A { int a; };
struct B : A { int b; };
auto b = B{.a=1, .b=2 };

On examine la grammaire qui semble, aux yeux de certains, demander de consommer la liste d'initialisation au complet avant de prendre une décisions sur la production à choisir (il y a des lectures divergentes de la grammaire ici). Ça semble être un changement mineur, mais sur le plan grammatical il y a beaucoup de conséquences à ce changement (quand on lit une accolade ouvrante, les possibilités de productions deviennent soudainement beaucoup plus nombreuses).

(un des membres présents sur place signale que la pièce a une fenêtre, chose rare chez CWG, et que c'est une distraction...)

Une partie des efforts investis vise à éviter des ambiguïtés. Par exemple :

struct A { int a1, a2; };
struct B : A { int b; };
struct C : A { int a1; };

B v1 = B{ .a1=1, .b=2 };         // the explicitly initialized elements are [A, B::b]
B v2 = B{ .a1=1, .a2=2, .b=3 };  // the explicitly initialized elements are [A, B::b]
B v3 = B{ A{ 1, 2 }, .b=3 };     // the explicitly initialized elements are [A, B::b]
B v4 = B{ A{}, .a2=1, .b=3 };    // error: A initialized two different ways
C v5 = C{ .a1=4 };               // the explicitly initialized elements are [C::a1]

La gestion des agrégats dont l'initialisation est « aplatie » est discutée :

struct A { int a; };
struct B : A { int b; };
struct C : B { int c; };

// the A element is initialized from {.a=1}
B x = B{ .a=1 };

// the B element is initialized from {.a=2, .b=3}
// which leads to its A element being initialized from {.a=2}
C y = C{ .a=2, .b=3, .c=4 };

Dû au modèle objet de C++, il est important que les initialisations soient appliquées en ordre de déclaration, et les exemples préexistants doivent être ajustés pour tenir compte de cette nouveauté qui permet d'utiliser un designater initializer pour une classe de base :

struct A { int x; int y; int z; };
A a{.y = 2, .x = 1};                // error: designator order does not match declaration order
A b{.x = 1, .z = 2};                // OK, b.y initialized to 0

+   struct B : A { int q; };
+   B e{.x = 1, .q = 3};                // OK, e.y and e.z initialized to 0
+   B f{.q = 3, .x = 1};                // error: designator order does not match declaration order

+   struct C { int p; int x; };
+   struct D : A, C { };
+   D g{.y=1, .p=2};                    // OK
+   D h{.x=2};                          // error: ambiguous lookup for x

+   struct NonAggr { int na; NonAggr(int); };
+   struct E : NonAggr { int e; };
+   E i{.na=1, .e=2};                   // error: the lookup set for na finds NonAggr, which is not an aggregate base of E

(pause du dîner; il est 6 h du matin à Montréal; j'en profite pour réveiller Ludo qui doit aller à l'école et faire un petit-déjeuner à mon amoureuse Za)

On poursuit les travaux. Hubert Tong avait des préoccupations sur certaines phrases mais n'était pas présent ce matin alors on profite de son arrivée pour éclaircir celles-ci. En gros, en transformant le texte, on semble avoir perdu un peu du sens du texte d'origine et c'est embêtant. On travaille sur la formulation un peu plus de 30 minutes...

Certains ajustements de dernière minute sont faits (la proposition visait à l'origine C++26 alors certains aspects parlent de C++23 qui était alors le standard officiel, mais nous sommes désormais à C++26 alors on fait une mini mise à jour de ces passages).

P0876 – fiber_context - fibers without scheduler

L'enjeu ici est le souhait de faire en sorte qu'une exception levée sur une fiber demeure sur cette fiber. Les changements proposés sont petits mais on travaille pour faire en sorte que le texte soit le plus clair possible. L'interaction avec setJens Maurerp()/longJens Maurerp() est aussi explorée (changer de fiber en chemin est UB). On mentionne (comme je l'ai appris à la dure à travers certaines de mes propres propositions par le passé) qu'il est difficile de bien parler de certains aspects de l'exécution d'un programme sans parler de la pile d'exécution, or la machine abstraite de C++ ne suppose pas de pile...

On examine ensuite l'interaction entre les fibers et les signal handlers. C'est un autre truc qui est plus ou moins clairement défini dans le langage, alors c'est difficile à bien circonscrire ici.

Davis Herring fait remarquer qu'il nous faut des mots pour éviter qu'une implémentation n'évalue de manière préventive du code avant que ce ne soit correct de le faire, ou pour empêcher que la résomption d'une fiber ne se fasse avant son point de suspension, ce qui ne semble pas être le cas en ce moment. Jens Maurer précise que les mots actuels ne semblent pas empêcher qu'une implémentation ne change de fiber profondément dans une séquence d'appels de fonctions. Il est possible que ces possibles problèmes tiennent à l'interaction entre coroutine et fiber, plus spécifiquement au fait qu'une coroutine peut changer de thread alors qu'une fiber ne le peut pas, or un thread exécute un fiber... L'auteur va travailler sur cet aspect plus tard.

On a un passage qui dit « a thread is always running exactly one fiber ». Hubert Tong questionne le choix de « running » qu'on utilise très peu dans le standard. Davis Herring fait remarquer que « running fiber » n'est pas un terme défini. On discute des interactions entre fibers en les algorithmes par_unseq (brrrr...). Davis Herring suggère d'écrire fiber resumption is vectorization-unsafe pour le moment.

P2153 – Forbid defaulting operator=(X&&) &&

Le texte actuel permet d'utiliser des ref-qualifiers sur l'affectation (de mouvement, mais aussi sur l'affectation de copie; on critique le titre de la proposition). Le proposition est de l'interdire. C'est un truc très niché et qui est source de confusion, car cela permet des aberrations comme :

A& operator=(const A&) && = default

On passe beaucoup de temps sur la formulation des phrases (il y a beaucoup de sortes de références dans chaque énoncé, ça peut devenir lourd). Éventuellement, on arrive à la pause de l'après-midi alors j'en profite pour faire une tournée de distribution de verdure aux rongeurs et aux lagomorphes de la maison (mon amoureuse me demande d'en donner un peu à Patapon, le conure qui « m'aide » pendant nos travaux en se perchant sur mon épaule et en attaquant mes écouteurs, alors je procède).

Je laisse des remarques sur des petites erreurs remarquées sur des propositions ce matin (j'ai manqué le début alors j'ai vu des trucs a posteriori).

L'annexe C contiendra cet ajout (avec explications) :

struct S{
    S& operator=(const S&) && = default; //ill-formed; previously well-formed
};
struct T{
    T& operator=(const T&) const = default; //ill-formed; previously well-formed but deleted
};
struct U{
    U& operator=(const U&&) = default; //ill-formed; previously well-formed but deleted
};

Ça prend forme.

P3423 – Extending User-Generated Diagnostic Messages

La proposition est de permettre la génération de messages à la compilation, comme ceux permis pour static_assert, pour les annotations [[deprecated]], [[nodiscard]] et les =delete.

On travaille sur le texte de la proposition. Entre autres, elle parle de string-like objects or l'idée de ces textes formatés à la compilation est de ne pas avoir de string object du tout, du moins au sens du mot object dans la machine abstraite.

Certains passages du texte de static_assert ont été déplacés pour fins de généralisation, mais on constate que cela a des conséquences (l'emplacement choisi visait à ne pas demander la production des messages si ce n'est pas nécessaire; la réorganisation ajoute du travail parfois inutile à la compilation, et la position du passage préexistant résultait de nombreuses heures de débat). On veut aussi limiter la portée de ces messages produits à la compilation dans le but d'éviter que ceux-ci soient observables par le programme.

Un enjeu intéressant est que dans le cas de static_assert, on sait clairement quel est le point de génération du texte dans un programme alors que pour une annotation, c'est beaucoup moins évident de cibler un point en particulier.

On examine la question de savoir si la substitution d'un message de diagnostic dans une annotation fait partie du immediate context. C'est subtil... On demande l'ajout d'une combinaison de [[nodiscard(diagnostic-message)]] avec std::source_location.

Il reste du travail à faire ici.

P3899 – Clarify the behavior of floating-point overflow

Cette proposition attaque un aspect du standard qui n'a jamais été clair, soit le comportement d'un programme lorsque survient un débordement sur un nombre à virgule flottante. On a par exemple des cas de comportement indéfini. Ce qu'il est possible de faire avec std::numeric_limits<T>::infinity() est un peu circonscrit (merci à SG6!), mais demande aussi un peu d'amour. Ce flou mène à de nombreuses divergences d'implémentation (le comportement vers lequel on souhaite converger est celui de gcc 15).

Le choix de mots est tellement délicat quand on parle de nombres à virgule flottante, de valeurs représentables, d'infinité... Une part importante des problèmes relevés sont préexistants à la proposition, et proviennent du texte du standard du langage C il y a des décennies, et on est tentés le les corriger mais cela accroîtrait beaucoup la portée de le proposition alors on cherche des solutions plus humbles, quitte à accepter qu'elles soient temporaires.

L'examen des changements proposés se fait de manière minutieuse. On remarque par exemple que dans le cas des expressions arithmétiques, le cas des conversions implicites résultant de recours à un opérateur de conversion comme X::operator float() n'est pas couvert. Aussi, dans les règles à appliquer, une partie du travail est commun aux entiers et aux nombres à virgule flottante mais il semble que la terminologie choisie introduirait (involontairement) du comportement indéfini sur certaines opérations applicables à des entiers non-signés.

Le texte proposé se promène entre le domaine des nombres réels (pour le formalisme théorique) et celui des nombres à virgule flottante (pour la représentation), ce qui pose des problemes en soi aussi car certains mots sont applicables à l'un mais pas vraiment à l'autre. Entre autres, le domains des réels est total sauf pour la division alors toutes les opérations autres que celles-ci résultent en des réels, ce qui ne correspond pas à ce qu'on cherche à décrire ici pour les flottants.

(il se fait tard; on poursuivra demain)

Jour 1 – 9 juin 2026

Je ne serai présent que pour la première moitié de la journée aujourd'hui car je dois animer l'assemblée générale des enseignantes et des enseignants du Collège Lionel-Groulx en avant-midi, heure de Montréal.

Pour débuter la journée, on poursuit les travaux sur les débordements lors d'opérations sur des nombres à virgule flottante.

P3899 – Clarify the behavior of floating-point overflow

Le premier ajustement de la journée est l'ajout d'un renvoi vers [expr.mul] pour clarifier un truc. On note aussi que nous avons un exemple avec std::float32_t mais l'existence de ce type n'est pas garantie de manière portable alors on ajoute quelques mots pour clarifier cela. ¸Toujours pour s'amuser, C++ ne garantit pas IEEE 754 (ISO/IEC 60559) car on supporte des systèmes embarqués trop humbles pour quelque chose d'aussi ambitieux alors il faut mettre des gants blancs dans les exemples.

Amusant : on n'a pas de mots qui expliquent comment diviser un flottant par zéro donne un infini... Ouf.

Tout ce qui peut mener à du comportement indéfini est sujet à exclusion des contexte constexpr alors on prend soin de le noter aux endroits appropriés.

On discute des nuances entre les quiet NaN et les signaling NaN, mais je ne m'y connais pas assez pour participer à cet aspect de la discussion.

Davis Herring rappelle qu'on partage une grande partie des mathématiques avec le langage C alors tout ce qu'on fait ici est un peu apeurant.

On apporte ça pour vote samedi. Ce sera un DR.

P2719 – Type-aware allocation and deallocation functions

L'idée, dans une optique de sécurité accrue pour certains types, est d'offrir des déclinaisons des opérateurs new et delete qui soient conscientes du type à gérer. Par exemple :

void* operator new(std::type_identity<mylib::Foo>, std::size_t n, std::align_val_t align) {
  ...
}
void operator delete(std::type_identity<mylib::Foo>, void* ptr, std::size_t n, std::align_val_t align) {
  ...
}

... ou encore, dans le cas d'un template : 

template <class T>
  requires use_special_allocation_scheme<T>
void* operator new(std::type_identity<T>, std::size_t n, std::align_val_t align) { ... }

template <class T>
  requires use_special_allocation_scheme<T>
void operator delete(std::type_identity<T>, void* ptr, std::size_t n, std::align_val_t align) { ... }

On a quelques débats terminologiques : devrait-on parler de allocation function, template allocation function (ceci existe-t-il vraiment?), allocation operator...?

Ce qui rend une fonction d'allocation ou de déallocation type-aware est la présence d'un premier paramètre de type std::type_identity<T>. On a d'ailleurs cet exemple qui met en lumière les subtilités de ce choix :

template <typename T>
using A = std::type_identity<T>;

template <typename U>
void* operator new(A<U>, std::size_t, std::align_val_t);    // not a type-aware allocation function

template<typename T>
struct W {
  using B = std::type_identity<T>;
};

template <typename U>
void* operator new(W<U>::B, std::size_t, std::align_val_t); // not a type-aware allocation function

template <typename X>
class S {
  using C = std::type_identity<X>;
  void* operator new(C, std::size_t, std::align_val_t);     // a type-aware allocation function
};

Notez que S<X>::C est fondamentalement différent de A ou de W<T>::B.

On rappelle que désormais, denotes implique non-explorable par réflexivité alors que designates permet cette exploration. Ici, ça nous permet de savoir si une Splice peut être utilisée ou pas.

Jens Maurer demande ce qui se produit si on offre une fonction d'allocation type-aware sans offrir une fonction de déallocation type-aware. Les auteurs pensent que ça devrait être une Hard Error, mais c'est pas l'état de la situation dans le reste du langage.

On a une formule qui m'embête sur le nombre minimal de paramètres pour une fonction d'allocation template (ça indique deux, dont le premier est un size_t exprimant la taille en bytes), car je ne vois pas bien sur quoi la déduction du type du template se fera, mais on peut appliquer un template sur les paramètres suivant les deux premiers... C'est créatif!

On note qu'une fonction de déallocation type-aware ne peut pas être un destroying delete (les règles de signature ne le permettent pas), mais je pense que c'est Ok.

L'alignement est un requis pour ces fonctions, pas une option.

(brève pause du matin; j'en profite pour sortir mon chien Pauline et la nourrir)

On continue l'exploration de cette proposition. L'algorithme pour choisir la fonction d'allocation la plus appropriée a été retravaillé, et c'est en général très bien, mais ça interagit avec plusieurs facettes subtiles du langage (dont le name lookup) alors on prend le temps de bien faire les choses. Entre autres, le texte proposé semble avoir échappé la vérification de contraintes (on pense pouvoir résoudre ce problème en déplaçant quelques paragraphes là où cela deviendrait implicitement fait).

Il reste du travail à faire. À suivre pour celle-ci...

P3668 – Defaulting Postfix Increment and Decrement Operations

L'idée ici est que, considérant qu'on implémente presque toujours operator++(int) sur la base de operator++(), pourquoi ne pas permettre d'écrire operator++(int)=default?

C'est une bonne idée. On fait le tour de la proposition pour la polir un peu et s'assurer que le texte porte clairement l'intention. Plusieurs subtilités sont discutées (par exemple, à quel moment =default signifie-t-il =delete? Quel est le comportement quand on écrit operator++(int) mais on ne définit par operator++()?). J'avais pas réalisé mais les enum ont operator++ alors que les enum class ne l'ont pas, du moins par défaut.

On finit le matin. Je vais manquer des sujets vraiment intéressants cet après-midi (j'ai hâte de lire les notes sur le Wiki!), par exemple les opérations invalides sur les pointeurs et les enjeux de provenance de pointeurs...

Jour 2 – 10 juin 2026

Je manque les premières minutes (il est très tôt et c'est difficile de démarrer le corps). À mon arrivée, on discute de Core Issues (j'ai peut-être manqué les premières).

Core Issue 3103: Corresponding members and by-value object parameters

Étrangeté. Ceci compile :

struct K {
  void f(this K);
  void f();
};

... mais ceci (qui est la même chose) ne compile pas :

struct K {
  void f(this OK);
  void f() &;
};

Les deux ne devraient pas compiler. Je ne sais pas ce qui a été discuté (je gérais Pauline le chien qui avait besoin de sortir à 2 h 40 du matin...)

 Core Issue 2228: Ambiguity resolution for cast to function type

Ceci ne compile pas :

int x = (int()) + 5;

... dû à une ambiguïté grammaticale. Dans la même veine, ceci mène à des divergences d'implémentation :

struct T { int operator++(int); T operator[](int); };
int a = (T()[3])++; // not a cast

Conséquence de ce problème :

(S())[]->A<int>;              // OK, constructor call
(S())[]->A<int> {return {};}; // error: C-style cast of lambda

Avec le changement de grammaire proposé, on arrive à :

template <class T> struct X {};
template <int N> struct Y {};
X<int()> a;   // type-id
X<int(1)> b;  // expression (ill-formed)
Y<int()> c;   // type-id (ill-formed)
Y<int(1)> d;  // expression
void foo(signed char a) {
  sizeof(int());    // type-id (ill-formed) expression
  sizeof(int(a));   // expression
  sizeof(int(unsigned(a)));    // type-id (ill-formed) expression
  (int())+1;              // type-id (ill-formed) expression
  (int(a))+1;             // expression
  (int(unsigned(a)))+1;   // type-id (ill-formed) expression
}
typedef struct Brian Bi { int C[2]; } *B, C;
void g() {
  sizeof(B()->C[1]);     // OK, sizeof(expression)
  sizeof(auto()->C[1]);  // error: sizeof of a function returning an array ill-formed expression
}

Ce à quoi on arrive semble satisfaire le groupe.

Core Issue 2864: thread_local dynamic initialization

Le texte existant ne dit pas clairement comment traiter ceci :

extern thread_local constinit int x;

On s'attend à ce qu'il n'y ait pas de « wrapper code » pour avoir une initialisation paresseuse dans ce cas (c'est même l'une des intentions derrière l'introduction de constinit!) mais le texte à ce sujet n'est pas clair. Le changement proposé (ajouter trois mots!) semble satisfaisant.

 Ready.

Core Issue 2756: Completion of initialization by delegating constructor

Le texte décrivant quand une construction se termine dans le cas d'une construction par délégation manque un peu de clarté. La proposition est de faire en sorte que dans un cas comme :

struct X {
  X() : X(0) { // #1
  }
  X(int) { // #2
  }
};
X x; // #0

... l'appel #0 mène à la construction de l'objet à la fin de #2 (même si #1 en soi n'est pas terminé).

Core Issue 2974: Non-deduced context for qualified-id naming a template

Le texte sur les contextes non-déduits semble incomplet :

template <template <typename> class>
  struct B;

struct C {
  template <typename> struct Nested;
};

template <typename T>
  void f(T *, B<T::template Nested> *);

void g(C *cp) {
  f(cp, 0);           // should be OK
}

Le correctif proposé semble Ok. Ready.

Core Issue 3023: Default arguments in list-initialization

Voici le cas soumis pour décrire le problème :

#include <iostream>
struct I {
  I(int x) { std::cout << x; }
};
struct S {
  S(I, I = 2) {}
};
int main() {
  S(1, 2); std::cout << '\n';  // unspecified order; prints 12 or 21
  S{1, 2}; std::cout << '\n';  // prints 12 (9.5.5 [dcl.init.list] paragraph 4)
  S{1};                        // ???
}

Le texte ne dit pas clairement quoi faire dans le dernier cas (c'est le traitement du paramètre avec valeur par défaut qui n'est pas spécifié). On clarifie le propos. Dans cet exemple, S{1} devrait afficher 12.

Ready.

Core Issue 3027: Equivalence of pack-index-specifiers

Le texte décrivant comment, pour un pack T, l'écriture T...[constant-expression] forme un type value-dependant unique ne dit pas correctement si deux écritures avec la même valeur donnent le même type tel qu'observable avec decltype.

Core Issue 3046: Enumerations as part of the common initial sequence

On a un cas particulier ici :

#include <iostream>
#include <type_traits>

enum E { E0 } e;
enum F { F0, F1, F2, F3 };
static_assert(std::is_same_v<std::underlying_type_t<E>, std::underlying_type_t<F>>);  // assume this passes

struct A { E e; };
struct B { F f; };
union U {
  A a;
  B b;
} u;

bool test() {
  return u.a.e == 2;
}

auto ptest = test;

int main() {
  u.b.f = F2;
  std::cout << ptest();
}

Puisque E et F ont le même type sous-jacent, mais l'étendue des valeurs devant être supportées pour E requiert un bit alors que celle pour F requiert deux bits, est-ce que la common initial sequence s'arrête avant ou après a.e et b.f?

La résolution proposée est d'accepter la participation à la common initial sequence seulement si les deux énumérations ont les mêmes valeurs.

On se demande si les énumérations avec type sous-jacent explicite sont couverts correctement, mais en pratique quand on a un type sous-jacent explicite l'ensemble des valeurs possibles est équivalent à celui du type sous-jacent. L'enjeu ici est que le type sous-jacent implicite est au choix du compilateur et dépend des valeurs énumérées.

Ready.

Core Issue 3146: Usual arithmetic conversions for enumerations are different in C

Hubert Tong a remarqué une différence entres les enum des deux langages quand le type sous-jacent est implicite. Il propose un ajout à l'annexe C :

typedef enum { E0 } E; // the underlying type of E can be unsigned int
static_assert(((E)E0 - 1 < 0) == (E0 - 1 < 0), "Must pass for C++");

Ce qui se passe est que les règles de promotion arithmétiques appliquées par les deux langages diffèrent.

Core Issue 3159: Instantiation of variables with incomplete array types

Le problème relevé va comme suit :

// Case 1: Clang rejects because the type of `*p` changes
// between redeclarations; Clang seems to be incorrect:
// The array bound affects the semantics of the program.
template<typename T> struct X {
  static inline int arr[] = {1, 2, 3};
};

// Clang does not instantiate a definition here.
extern decltype(X<int>::arr) *p;
// Clang does instantiate a definition here.
int n = sizeof(X<int>::arr);
decltype(X<int>::arr) *p;

// Case 2: GCC, EDG, MSVC reject because they instantiate a definition
// of `X<int>::arr` even though it's not odr-used and doesn't appear to
// affect the semantics of the program.
template<typename T> struct X {
  static inline int arr[] = {1, 2, T::error};
};

// The array bound here doesn't matter; array-to-pointer decay doesn't
// care about it.
decltype(+X<int>::arr) r;

// Case 3: GCC and clang accept; MSVC rejects because it instantiates a definition
// of X<int>::arr even though it's not odr-used and its type is complete.
// EDG rejects because it instantiates the definition of arr while instantiating X<int>.
template<typename T> struct X {
  static inline int arr[3] = {1, 2, T::error};
};

// No definition needed, thus the initializer is not instantiated.
decltype(+X<int>::arr) r;

Avec la résolution proposée, on aurait :

template<typename T> struct X {
  static inline int arr[] = {1, 2, T::error};
};
decltype(+X<int>::arr) r;  // error: definition of X<int>::arr is instantiated to complete its type

template<typename T> struct X2 {
  static inline int arr[3] = {1, 2, T::error};
};
decltype(+X2<int>::arr) r;  // OK, type of arr is complete and arr is not odr-used

Core Issue 3164: Location of specification of __STDCPP_FLOAT16_T__ macro

C'est un enjeu de manque de clarté quant à l'endroit où ces macros, décrivant la possible existence de mécanismes conditionellemement définis, devraient se trouver, et la formulation de leur valeur est boiteuse. On propose un correctif simple. On en a d'autres dans [cpp.predefined#2].

Davis Herring fait remarquer que pour une macro, l'idée même de « valeur » ne fait pas de sens (au mieux, on a une séquence de jetons), mais bon, passons.

Core Issue 3165: Use "equivalent type" to support templated entities

Petit accroc terminologique embêtant dans le cas de types dépendants. La proposition de correctif est simple (ça ressemble à un oubli).

Jason Merrill fait remarquer un lien avec la discussion sur same type vs equivalent type dans le cas des indices de packs, plus tôt. Ça amène une discussion plus étendue sur le choix du terme dans ce cas, mais surtout sur le bon endroit pour décrire cette réalité.

(brève pause du matin)

Après discussion avec John Spicer, Jens Maurer contextualise le débat quant à l'endroit où l'idée de same type dans le cas d'entities type-dependent devrait se positionner. Davis Herring fait un lien avec Core Issue 2 (sans blagues!), puis propose [temp.over.link#6.3]. On regarde aussi [temp.type#5]. Brian Bi mentionne Core Issue 2584 qui semble précisément nous orienter vers ce problème. Faudrait visiblement résoudre Core Issue 2584!

En attendant, on jongle avec l'idée spéculer qu'il y a une résolution à Core Issue 2584 et aiguiller les gens qui cherchent la définition de same type vers [temp.over.link] et travailler à une meilleure définition de same type dans le cas de types dépendants. Brian Bi pense qu'on devrait se limiter à equivalent types plutôt qu'à same types, mais il se trouve que same type est ce qu'on voit un peu partout dans le texte. Jason Merrill dit que dans le compilateur (du moins dans gcc), on demande « are these types the same type? » et que la solution se fait par équivalence d'expressions.

Davis Herring lance un pavé dans la mare et dit qu'à son avis, ce Core Issue n'est en fait pas un Issue : selon lui, la ODR résout ce problème en amont. Brian Bi voit un problème dans le cas des spécifications noexcept. On regarde [basic.link#11.1]

Après tout ce travail, on détermine que Core Issue 3165 est NAD. Et on blague un peu sur le fait que pour Core Issue 2, on a toujours « John Spicer drafting » après plus de vingt ans!

Core Issue 3166: Protected access rule for a pointer-to-member from a reflect-expression

On a ce cas :

class A {
protected:
  void f();
};

struct B : A {
  static constexpr auto r = ^^A::f;
};

La question posée est : est-ce possible? On semble penser que si (B dérive de A après tout).

Ready.

Core Issue 3167: Initializing typedefs

Ark. Le langage dit (si on fait une lecture un peu hostile) que ceci est supporté, mais c'est pas le cas :

typedef int x = 0;

On regarde [dcl.decl.general#4] pour voir les productions grammaticales (notant au passage le lien entre le =0 et les spécifications de fonctions virtuelles pures, qu'on ne veut pas briser).

On a une solution relativement simple. Ready.

Core Issue 3168: Issues with integer conversion ranks

Le texte existant peut laisser entendre des faussetés sur char et bool. Ça va faire du bien de nettoyer peu ces passages. La proposition est de traiter char en fonction de son type sous-jacent (que ce soit signed char ou unsigned char) et de mieux formuler le rang de bool pour qu'il soit inférieur à celu ides autres types entiers.

Ready.

Core Issue 3174: Handling of friends in argument-dependent lookup

Ceci semble brisé depuis la refonte des règles de Name Lookup :

struct A;
namespace ns { int f(A&&); }
struct A {
  friend int ns::f(A&&);
};

int x = f(A{});

On a une proposition de correctif, mais ça semble aller un peu loin (Jason Merrill rapporte avoir expérimenté avec celui-ci et avoir constaté un bris des re-throw dans un contexte de module). Vlad Serebrennikov pense que Core Issue 2370 recoupe ce problème.

On propose ceci : https://godbolt.org/z/de1zPTEq7

namespace foo {
  template<typename T>
  void f(T) {}
  namespace bar {
    struct S {
      template<typename T>
      friend void f(T);
    };
  }
}

namespace foo_not_nested {
  template<typename T>
  void g(T) {}
}
namespace bar_not_nested {
  struct S {
    template<typename T>
    friend void foo_not_nested::g(T);
  };
}

int main() {
  // Was this intended before? Will be allowed with CWG3174(?)
  foo::bar::S s0{};
  f(s0);
  // Not intended, CWG3174 prevents?
  bar_not_nested::S s1{};
  g(s1);
}

Les mots de la solution semblent suffire pour certains de ces cas mais pas tous. Jason Merrill pense que ce qui est proposé brisera libstdc++. On va retravailler le tout et consulter EWG.

Core Issue 3176: Sequencing default arguments during constant evaluation

Le texte n'est pas clair sur l'ordre d'évaluation des paramètres dans ce contexte quand certains de ceux-ci ont des valeurs par défaut. On clarifie l'intention (c'est quelque mots).

Ready.

Core Issue 3177: Formation of a header-name preprocessing token

Les règles en vigueur constituent une définition circulaire. Faut corriger ça. On valide la proposition de résolution.

Ready.

Core Issue 3179: More edge cases for a void function parameter

One examine ceci :

  template<class T>
  struct S {
    using U = decltype((void)(T*)0);
    void f(U);   // #1
  };
  template<class T>
  void S<T>::f() {}  // redeclaration of #1?

... et cela :

  template<class T>
  struct S {
    void f(std::void_t<T*>);  // #1
  };
  S<int> x;  // #1 is a zero-parameter function or has an ill-formed parameter of type void

C'est un truc qui résulte de travaux du passé pour faciliter la compatibilité avec C où les paramètres void sont communs, mais c'est embêtant en C++. On veut lever l'ambiguïté.

On se demande si same type as void ou type equivalent to void serait à privilégier ici. Un des enjeux est que C n'a pas de types dépendants alors que nous, si.

La résolution proposée donnerait :

template<class T>
struct S {
  void f(std::void_t<T*>);  // #1
};
S<int> x;  // error: #1 has a parameter of type void

template<class T>
struct S2 {
  void f(std::void_t<int*>);  // #2
};
S2<int> y;  // OK, #2 is a zero-parameter function

Il y a de la résistance devant cette direction (l'enseigner sera douloureux : void n'a pas le même sens dans un contexte dépendant ou pas). On met Ready mais ça pourrait changer (on va consulter EWG).

Core Issue 3182: Notional template parameters introduced for an array parameter

On a une formulation étrange dans la déduction des types d'une initializer_list qui laisse entendre que les types pourraient ne pas tous être les mêmes. Le texte proposé semble avantageux (et est plus court que ce qu'il remplace!)

Ready.

(pause du dîner; je fais le déjeuner de Za et de Ludo, un peu de vaisselle, etc. puis je reviens au poste)

Core Issue 3183: No expressions in an expression-list

C'est bête, mais on utilise expression-list quelque part alors qu'on aurait dû utiliser initializer-list. On corrige ça.

Ready.

Core Issue 3184: Pointer arithmetic with similar types

On a ceci qui est ill-formed mais devrait fonctionner :

char**p;
int diff = p - (const char * const *)p;

Le changement requis est mineur et allège le texte. Quelqu'un signale que le code est rejeté par tous les compilateurs « majeurs », mais l'avis majoritaire dans la salle est que ça devrait être Ok alors on applique le correctif demandé.

Ready.

Core Issue 3186: Argument-dependent lookup is for a name

On a ceci :

namespace N {
  struct C {
    friend void f(C);
    friend void g(C);
  };
}

void h() {
  f(N::C{});
}

Il se trouve que le texte ne semble pas dire que le name-dependent lookup utilise le nom dans sa recherche, ce qui est... étrange.

Le correctif proposé semble correct. Ready.

Core Issue 3188: Behavior change for class template argument deduction

On parle d'un changement à CTAD dans le traitement des classes de base, ce qui entraîne le besoin d'un ajout à l'annexe C car ça peut briser du code préexistant :

template<typename T>
  struct B {
    B(T);
  };

template<typename T>
  struct D : B<T *> {
    D(T);
    using B<T *>::B;
    T m = "a";   // #1
  };

D d("");       // ill-formed at #1 (T deduced as const char); previously well-formed (T deduced as const char*)

Ready.

Core Issue 3190: Ambiguous lookup for type aliases in reflection

On a ceci :

namespace A {
  using T = int;
}
namespace B {
  using T = int;
}
using namespace A;
using namespace B;
T t;                // #1, OK
auto r = ^^T;       // #2, ???

De manière un peu surprenante (pour moi, du moins), CWG et EWG sont tous deux d'accord pour accepter que le compilateur puisse choisir l'une ou l'autre des deux options ici :

namespace A {
  using T = int;
}
namespace B {
  using T = int;
}
using namespace A;
using namespace B;
T t;                // #1, OK
auto r = ^^T;       // #2, OK, represents either A::T or B::T

Ready.

P3822 – Conditional noexcept specifiers in compound requirements

L'idée est de simplifier l'écriture d'un requis noexcept dans une expression requires. Au lieu de ceci :

template<typename F, bool noexc>
concept invocable = noexc
  ? requires(F f) { { f() } noexcept; }
  : requires(F f) { f(); };
template<bool noexc>
struct callable_ref {
  callable_ref(invocable<noexc> auto&& fn);
  [...]
};

... on pourrait écrire cela :

template<typename F, bool noexc>
concept invocable = requires(F f) {
  { f() } noexcept(noexc);
};
template<bool noexc>
struct callable_ref {
  callable_ref(invocable<noexc> auto&& fn);
  [...]
};

Ça nous fait travailler dans la description des clauses noexcept conditionnelles et dans les signatures de fonctions. Ça vaut la peine car ça permet de simplifier les ajouts mentionnés dans la proposition et de réduire la redondance. Les auteurs devront apporter les ajustements suggérés (des simplifications pour l'essentiel) et revenir avec une autre version, probablement plus tard cette semaine.

P3891 – Improve readability of the C++ grammar by adding a syntax for groups and repetitions

C'est le gros changement grammatical annoncé en début de semaine. On nous présente le tout, mais il y a de la résistance (les gens dans la salle sont habitués à lire la grammaire dans sa forme traditionnelle après tout!)

Une critique est que la syntaxe proposée utilise des symboles inhabituels et des indices « à la mathématique » (des subscripts) alors pour les gens qui tendent à citer la grammaire dans le cas de leur travail, ça peut être un irritant. C'est une discussion assez longue, mais constructive car elle oriente les travaux futurs (c'est pas le genre de truc qui va être adopté cette semaine car c'est plutôt révolutionnaire).

Jens Maurer voit deux axes de travail, soit le groupement et le séquencement. Il demande un vote indicatif de la salle pour chacun (c'est rare qu'on fait des votes chez CWG!). C'est très partagé pour le séquencement et plutôt défavorable pour le groupement.

P3367 – constexpr coroutines

C'est une proposition qui a vécu plusieurs révisions mais qui semble avoir atteint la maturité. Le terme constexpr-suitable qui était dans le standard spécifiquement pour disqualifier les coroutines dans un contexte constexpr disparaît du texte du standard. L'air de rien, ça simplifie le texte à plusieurs endroits car ça supprime des cas d'exceptions.

(j'ai perdu un peu de la discussion dû à la gestion de dossiers familiaux)

Sans grande surprise, les allocations et déallocations de mémoire associées à « l'exécution » d'une coroutine à la compilation sont élidés.

À suivre pour ce dossier.

P3822 – Conditional noexcept specifiers in compound requirements

On revient sur cette proposition car on a une nouvelle version sous la main. Cet exemple est légèrement modifié :

void f() noexcept(sizeof(char[2])); // error: narrowing conversion of value 2 to type bool
void g() noexcept(sizeof(char));    // OK, conversion of value 1 to type bool is non-narrowing

On a une nuance grammaticale à l'effet qu'une fonction peut avoir une spécification d'exception mais un type de fonction ne le peut pas. Ça complique l'expression des requis dans la prose du standard. On a encore de petits changements à faire.

P3658 – Adjust identifier following new Unicode recommendations

Cette proposition nous rapproche d'une harmonisation des standards C++ et Unicode. On vise à définir les identifiants consommés par l'analyse lexicale sur la base des identifiants Unicode.

C'est amusant de voir cette jonction de deux cultures, après quinze ans d'efforts!

C'est une toute petite proposition (mais avec des conséquences). On se demande si ça devrait être un DR dans les circonstances. Ce le sera. Ready.

P2970 – Partial application of concepts in template arguments

Sachant ces deux formulations sont maintenant équivalentes :

template<invocable<int> T>
void f();
template<typename T>
void f() requires invocable<T, int>;

... la proposition est de faire en sorte que :

// soit la déclaration suivante:
template <typename T, template <typename> concept C>
constexpr bool b = C<T>;
// alords cette spécialisation:
b<double, concept std::convertible_to<int>>;
// ... serait réécrite par injection des paramètres passés au concept
template<>
constexpr bool b<double, concept convertible_to<int>> = convertible_to<double, int>;

... soit effectivement comme si on avait défini un nouveau concept :

template <typename T>
concept convertible_to_int = convertible_to<T, int>;

En fouillant un peu, certains voient des risques d'en arriver à des ambiguïtés. On nous rappelle toutefois que EWG souhaite l'ajout de ce mécanisme. Ça explique d'ailleurs le mot concept à certains endroits novateurs. On veut éviter ceci :

template <bool B> void f();
template <template <typename> concept C> void f();
f<invocable<int>>(); // boolean or partially applied concept?

En résumé, donc :

some_template_name <
  std::regular, /// can pass the name directly
  concept regular<>, // no reason this should not work
  invocable<int>, // That is a bool; it will get diagnosed.
  // If no overload or specialization, expect a bool.
  concept invocable<int> // ok
>;

J'essaie de prendre des notes mais la saisie des exemples est compliquée parce que ma souris se déplace sans peine, mais le « clic » cesse subitement de fonctionner. C'est très embêtant... Tout de même, ceci est joli :

template <class T, template <class> concept... Cs>
   concept all_of = (Cs<T> && ...);

Sans que je puisse tout noter (j'ai dû redémarrer mon ordinateur!), on constate des risques de problèmes avec le design choisi et une discussion avec EWT s'annonce à l'horizon.

La suite demain!

Jour 3 – 11 juin 2026

On commence par discuter de ce qui sera amené pour vote samedi. Il se trouve que P2434 – Nondeterministic pointer provenance, discuté en mon absence, y sera alors je devrai lire celui-là pour me familiariser avec lui avant le vote. On débat de l'intérêt d'en faire un DR ou pas. La situation est la même pour P3347 – Invalid Pointer Operations qui sera manifestement un DR aussi.

P3670 – Pack Indexing for Template Names

Exprimé par un exemple, on parle de permettre ceci :

template <template <typename> typename... TT>
struct S {
  template <typename T>
    using First = TT...[0]<T>;
};

Évidemment, ça implique des changements à la fois grammaticaux et sémantiques. Un des enjeux ici est de donner le bon sens au symbole '<' dans le parcours du texte du code source : quand est-ce un template et quand est-ce operator<()? Ici en plus, dans un pack (pas celui de l'exemple ci-dessus bien sûr, mais dans un trruc comme auto...Vs, on peut trouver des entiers!

On pense avoir trouvé un bogue préexistant dans le traitement des template template parameters, mais il y a dissension à ce sujet. C'est un niveau d'abstraction tellement élevé que c'est pas toujours clair...

Un pack et un élément d'un pack peuvent représenter diverses choses en fonction du contexte, et ce mécanisme (comme les autres du même acabit) interagit avec les mécanismes de name lookup alors on prend un peu de temps pour s'assurer que l'on n'a rien brisé.

P3606 – On Overload Resolution, Exact Matches, and Clever Implementations

On a une divergence d'implémentation avec le cas suivant :

template<typename T>
decltype([] { return T::x;}) f(T); // #1
void f(int) {} // #2
int main() {
  f(0);
}

Ici, gcc choisit #2 et ne tente pas #1, alors que c'est ill-formed avec les autres implémentations. De manière analogue, plusieurs ont des bug reports avec ceci :

struct S {
  template <typename T>
  requires std::copyable<T>
  explicit S(T op) noexcept; // #1
  S(const S&) noexcept = default; // #2
};
static_assert(std::copyable<S>);

Le problème est que ça passe avec gcc et le reste du monde se ramasse avec des plaintes. La proposition est donc de clarifier le comportement attendu pour réduire les divergences, et suggère un algorithme commun dans ces cas. Ça ajoute entre autres une clause [over.match.perfect] qui définit l'idée de perfect viable function. Vlad Serebrennikov signale que perfect viable function tel que défini est imparfait (il manque des trucs comme la satisfaction des contraintes) et suggère d'ajouter « a perfect viable function is a viable function » dans le texte, ce qui résout élégamment ce problème. Astucieux!

L'algorithme définit ce qu'est une better function (au sens de better than...) ce qui fait un peu rire la salle, mais dans le contexte où c'est défini ça peut fonctionner.

L'idée de chercher un perfect match est que si on trouve une fonction qui correspond pleinement aux besoins et qui n'est pas un template, alors on n'essaie pas de faire un match avec les alternatives génériques.

Une demande de la salle est de soumettre plus d'exemples. C'est le genre de subtilité avec laquelle on veut éviter d'échapper quelque chose qui nous explosera au visage une fois les changements implémentés.

Un examen plus approfondi de l'algorithme montre qu'avec ce qui est proposé, les templates demeurent dans la liste des candidats un peu trop longtemps alors on examine des approches pour réduire les efforts requis par le compilateur (et, conséquemment, accélérer la compilation ce qui est essentiel).

Jason Merrill fait remarque qu'un exact match est moins exigeant qu'un perfect match car un exact match accepte des correspondances avec variations de qualifications cv.

Ça va progresser, mais il y a du travail à faire alors ça va revenir, probablement lors de la rencontre de l'automne.

P3950 – return_value & return_void Are Not Mutually Exclusive

Ceci touche aux coroutines. Il se trouve que l'auteur a trouvé des cas où il est pertinent d'offrir les deux. Le changement terminologique requis est petit (c'est un ajustement à une note, pour l'essentiel) mais recoupe un endroit où on essayait de réduire la répétition des règles alors on s'intéresse à l'approche. Au passage, Jens Maurer fait remarquer que l'approche proposée peut mener un compilateur dans une situation d'où il ne peut pas récupérer. On travaille à solutionner ce problème.

(pause du matin)

Jason Merrill est d'avis que déclarer return_void()=delete; est quelque chose qu'on ne veut jamais faire.

Après beaucoup de discussions, on comprend que l'intention de EWG ici est de faire de ceci un nouveau mécanisme, pas un DR, pour faciliter l'évolution du code existant vers celui rendu possible désormais, alors on modifie la feature test macro associée.

P3733 – More named universal character escapes

On parle d'une simplification du texte découlant du fait que certains aspects terminologiques sont couverts par Unicode. Par exemple :

// Without abbreviations, we can form a "family: woman, woman, girl" 👩‍👩‍👧 emoji as follows:
u8"\N{WOMAN}\N{ZERO WIDTH JOINER}\N{WOMAN}\N{ZERO WIDTH JOINER}\N{GIRL}"
// With abbreviations:
u8"\N{WOMAN}\N{ZWJ}\N{WOMAN}\N{ZWJ}\N{GIRL}"

Autre exemple :

// Without abbreviations:
u8"INFO: Auto\N{SOFT HYPHEN}reconnect triggered due to network\N{NO-BREAK SPACE}timeout."
// With abbreviations:
u8"INFO: Auto\N{SHY}reconnect triggered due to network\N{NBSP}timeout."

On pense que c'est à la fois un DR et quelque chose qui demande un feature test macro, pour donner l'occasion aux implémentations de mettre en place le support requis.

P3950 – return_value & return_void Are Not Mutually Exclusive

L'auteur a fait quelques ajustements qu'on examine maintenant. Ça semble Ok. On convient ici encore d'avoir à la fois DR et feature test macro.

P3670 – Pack Indexing for Template Names

On revient sur celle-ci et on fait le tour des changements faits (il reste quelques coquilles, certaines divertissantes). Certains sont bêtement des erreurs de grammaire anglaise, mais ça arrive (la plupart des gens ici n'ont pas l'anglais comme langue maternelle, bien que la majorité aient une maîtrise impressionnante de cette langue, et nous faisons toutes et tous des erreurs à l'occasion).

Brian Bi s'interroge sur la pertinence de l'une des productions grammaticales. On regarde s'il est possible de simplifier ce qui est proposé (plus simple signifie souvent plus rapide, et le monde entier en bénéficie quand on y parvient). Après discussion, on se dit que s'il y a quelque chose à faire dans cette direction, ce sera le propos d'une proposition à part entière.

Ready. C'est pas un petit mécanisme, celui-là. Beau travail!

P3847 – Lexical order for lambdas

Le problème est que ceci n'est pas sécuritaire aujourd'hui :

void construction() {
  auto x = std::make_unique<int>();
  [value = *x,
   lifetime = std::move(x)] {};
}
struct last_call {
  std::function<void()> f;
  ~last_call() {f();}
};
void destruction() {
  auto x = std::make_unique<int>();
  const auto user = [&i = *x] {std::cout << i << '\n';};
  [lifetime = std::move(x),
   trigger = last_call{user}] {};
}

Notez les deux accès à x dans construction(), pour lesquels l'ordre d'évaluation n'est pas défini. On peut corriger ce bogue manuellement, mais c'est pas terriblement ergonomique :

void construction() {
  auto x = std::make_unique<int>();
  [both = std::pair{*x, std::move(x)}] {  // must be list-initialization
    auto &[value, _] = both;  // or use both.first throughout
  };
}

Davis Herring fait remarquer que la terminologie ici est plus complexe qu'elle ne le serait si nous étions plus explicites sur le fait qu'une lambda a des données membres (c'est ce qui se passe en pratique, mais c'est pas une obligation du texte du standard).

Le texte demande une évaluation de gauche à droite des entités dans le bloc de capture, ce qui correspond à un modèle « foncteur » des lambdas où l'ordre d'apparition des captures serait l'ordre de déclaration des variables membres. Cela ne s'applique qu'aux captures explicites (dans le cas des captures implicites, c'est pas vraiment un enjeu).

On cherche le niveau approprié de spécification : est-ce qu'indiquer l'ordre d'initialisation suffit ou doit-on aussi spécifier l'ordre de déclaration des variables membres? Le second serait ma préférence (plus facile pour raisonner, surtout pour ce qui a trait à l'ordre de destruction de ces variables).

P2243 – Language linkage for templates

Ok, c'est étrange. La proposition est intéressante à plusieurs égards (on y apprend beaucoup!), mais si on va à ce qu'elle cherche à permettre, on parle de :

extern "C" {
  template<class T> void f(T);
  template<class T> void g(void(T));
}
template<class T> void f(T) {}
template<class T> void g(void(T)) {}

... tout en interdisant ceci, qui est grammaticalement permis en ce moment mais ne fais pas de sens :

template<class> extern "C++" void f() {}

Quelqu'un blague qu'on devrait ajouter une entrée à l'annexe C, entraînant des réactions d'horreur viscérale dans la salle.

Le texte en soi est très petit, et dit en gros « you shall not do this ». Ready et DR. Ouf!

(pause du dîner; j'en profite pour faire un peu de lessive, puis je me fais à déjeuner et je fais de même pour Ludo et Za)

On examine un petit truc sur P3950 par mesure de prudence, puis on continue avec une nouvelle proposition.

P3956 – Undefined Behavior and IFNDR Annexes

On aura deux nouvelles annexes au standard pour répertorier, respectivement, les cas de comportement indéfini et de IFNDR explicitement mentionnés dans le texte. La proposition est massive (121 pages) car on a à la fois la démarche, les stratégies organisationnelles, le nouveau texte, les renvois dans le texte d'origine, etc.

On discute de la forme que prendront les noms stables de sections dans cette annexe. Pour le moment, on a des trucs comme [ubx:class.cdtor.before.ctor], et c'est peut-être Ok mais ça mérite discussion.

Quelqu'un signale que la structure choisie peut jouer des tours dans les quelques cas où du library UB se cache dans une section du Core Language et inversement.

On travaille sur la prose introduisant le propos pour éviter de surcharger des termes dont l'usage habituel est technique comme « in the main text » ou « to represent the issue ». On fait aussi quelques retouches plus cosmétiques comme transformer une énumération un peu longue dans un paragraphe en une série de puces pour faciliter la compréhension.

On semble tendre vers un vote pour samedi. Cool! C'est un truc sur lequel Shafik Yaghmour travaille depuis des années! Jens Maurer fait remarquer que cette annexe rendra l'ajout de comportement indéfini plus déplaisante dans le futur parce que l'obligation de le documenter imposera un fardeau sur les épaules des autrices et des auteurs (c'est une boutade, mais c'est pas faux).

On discute ensuite des liens entre ces annexes et l'effort en cours pour réduire les cas de comportement indéfini dans le langage.

P3670 – Pack Indexing for Template Names

Hubert Tong signale qu'il lui semble qu'il manque un passage (effacé par accident?) dans le descriptif de [temp.variadic]. On demande à l'auteur de corriger la situation.

P3847 – Lexical order for lambdas

On y revient. On a une formulation pour l'ordre de déclaration des variables membres de la fermeture qui se limite à dire que cet ordre est conséquent avec celui des captures correspondantes. Hubert Tong signale que la forme est plus ou moins à propos s'il n'y a pas de captures, alors on retouche un peu.

Avec le texte proposé, ceci fonctionne :

void f(std::vector<int> &&v) {
  [size = v.size(),
   own = std::move(v)] {};
}

... car size est initialisée avant own et a donc la valeur de v avant le mouvement.

Les phrases sont longues et complexes (mais semblent correctes) alors on essaie de faire un effort de simplification. C'est beaucoup de travail.

Ready, DR. Ça correspond à ce que font nos implémentations de toute manière.

P3670 – Pack Indexing for Template Names

L'auteur a retrouvé le passage disparu. Ouf!

Hubert Tong remarque que la production simple-template-name introduit des éléments context-dependent ce qui signifie que [gram.key] dans l'annexe A aura besoin de retouches. Les occurrences de template-name auront pour la plupart à être remplacées par simple-template-name.

(pause de l'après-midi; Hubert Tong remarque soudainement l'étrange présence de fenêtres dans la pièce)

Jens Maurer annonce qu'un autre enjeu avec P3670 a été découvert pendant la pause. En effet, dans [dcl.type.simple] la définition de template-name est incompatible avec ce qui serait son nouveau rôle. On recule sur le Ready dans les circonstances.

P3424 – Define Delete With Throwing Exception Specification

Le sous-titre est « Addressing one undefined behavior at a time ». En gros, on a noexcept(true) sur ces opérateurs, mais si on fait noexcept(false) ça donne du comportement indéfini alors on suggère de rendre ça ill-formed.

Ça entraîne plusieurs petits changements ici et là car le traitement des destructeurs et des fonctions de déallocation est un peu spécial en comparaison avec le reste du standard. Il faut aussi s'assurer d'avoir l'effet souhaité (selon les mots choisis, on peut finir avec du ill-formed ou du « sans effet »).

Alisdair Meredith suggère d'en faire un DR, peut-être reculant à C++11, et pense qu'on pourrait faire l'économie d'un ajout à l'annexe C mais Hubert Tong signale que les standards précédant C++29 ont existé et pense que l'ajout à l'annexe C demeure nécessaire. Il n'y a pas de consensus envers un DR dans ce cas.

Il y a une erreur dans un des exemples (un operator delete(T*) plutôt que operator delete(void*)). On corrige.

Le titre de la proposition est modifié pour devenir « Deallocation Functions With Throwing Exception Specification are Ill-formed ». On examine les plus récents ajustements, et on finit par en arriver à quelque chose d'acceptable.

Ready.

P3310 – Solving issues introduced by relaxed template template parameter matching

Il semble qu'il manque un tie-breaker dans certains cas où les spécialisations partielles sont difficiles à distinguer. Par exemple :

template <template <class   > class TT> void f(TT<int>); // #1
template <template <class...> class TT> void f(TT<int>); // #2

template <class   > struct A {};
template <class...> struct B {};
void test() {
  f(A<int>()); // selects #1 because it is more specialized.
  f(B<int>()); // selects #2, see above.
}

Il y a plusieurs cas dans la proposition, la plupart compliqués (p.ex. : un template à plusieurs paramètres dont un avec valeur ou type par défaut) :

template<class T1> struct A;

template<template<class T2> class TT1, class T3>
struct A<TT1<T3>>; // #1

template<template<class T4, class T5> class TT2, class T6, class T7>
struct A<TT2<T6, T7>> {}; // #2

template<class T8, class T9 = float> struct B;
template struct A<B<int>>;

C'est un enjeu de partial ordering, pas de viabilité.

(j'ai manqué un peu de discussion dû à un appel pour les rénovations de la maison)

On travaille plus d'une heure sur la définition d'un algorithme correctement exprimé. De un, le niveau d'abstraction et de généricité est très élevé (deux, souvent trois niveaux) et de deux, les phrases sont complexes en soi, et on parle de templates inventés pour fins synthétiques. Reformuler, nommer les choses, simplifier... C'est beaucoup de travail et il est facile de perdre le fil, d'échapper l'objet du discours. On essaie de comprendre la mécanique malgré tout. Heureusement, ça se fait dans la bonne humeur.

On passe beaucoup de temps sur l'exemple suivant, pour lequel #2 était originalement choisi et #1 l'est depuis l'adoption de P0522; la présente proposition vise à restaurer le choix de #2 dans ce cas :

template<class T1, class T2 = float> struct A;
template<class T3> struct B;

template<template<class T4> class TT1, class T5>
struct B<TT1<T5>>; // #1

template<template<class T6, class ...T7s> class TT2, class T8, class ...T9s>
struct B<TT2<T8, T9s...>> {}; // #2

template struct B<A<int>>;

Sachant que l'état actuel des choses est brisé et que les compilateurs essaient de contourner le problème, ceci est probablement un DR et on n'a probablement pas à modifier la feature-test macro associée.

P3657 – A Grammar for Whitespace Characters

Le sous-titre est « Resolution for NB comment US 5-108 ». On touche le traitement des blancs dans l'analyse lexicale du code source. On jette un premier coup d'oeil mais la journée est terminée alors le reste se fera demain.

Jour 4 – 12 juin 2026

On commence à l'heure. Ce sera une étrange journée aujourd'hui car je vais manquer une part importante de l'après-midi dû à des enjeux familiaux. On discute de l'opportunité de traiter P1839 – Accessing object representations mais cette proposition risque de demander plus de temps que la journée qu'il nous reste cette semaine (tristement).

P0876 – fiber_context - fibers without scheduler

Il y a un changement clé au paragraphe [intro.execution#12] qui demande notre attention (passer de « thread » à « fiber »; juste un mot, beaucoup de conséquences car ça interagit avec la mécanique de levée d'exceptions). On examine la manière dont context switch est défini et on jongle avec l'idée d'expliciter fiber context switch. On joue avec l'idée de séquencement des opérations dans un fil d'exécution et à travers les fils d'exécution alors l'important est de spécifier nos attentes, ce qui doit être fait, mais de ne pas se mêler du « comment ».

Nat Godspeed essaie "All evaluations sequenced before a fiber context switch in fiber A are sequenced before any evaluations sequenced after the fiber context switch in fiber B." pour démarrer la discussion. Roger Orr essaie pour sa part "When a running fiber A resumes a fiber B all evaluations sequenced before the fiber context switch in A are sequenced before any evaluations in B sequenced after the fiber context switch in B.". Jens Maurer tente "For a context switch from fiber A to fiber B, all evals sequenced before the switch in A are seq before any evals in B that are sequenced after the switch."

Nat Godspeed relance ensuite avec "Given a fiber context switch from fiber A to fiber B, all evaluations sequenced before that fiber context switch in A are sequenced before any evaluations in B that are sequenced after that fiber context switch in B." et ça semble rencontrer l'assentiment généralisé.

On constate que la passage de l'exécution d'un fiber à un fiber successeur est aussi un context switch. Que dire pour le cas du dernier fiber sur un thread? Nat Godspeed suggère de mettre des mots particuliers distinguant le default fiber qui est exécuté au démarrage d'un thread pour résoudre cette question.

On jongle avec l'idée d'utiliser default fiber ou initial fiber (of a thread). Certains craignent qu'il y ait confusion avec default fiber dû à l'utilisation du terme default à plusieurs sauces dans le texte du standard, mais peut-être que ça peut fonctionner avec des références croisées.

On reverra celle-ci.

P3822 – Conditional noexcept specifiers in compound requirements

On examine les changements apportés pour voir s'ils correspondent aux attentes. Ça fonctionne. Ready.

P3097 – Contracts for C++: Virtual functions

Ceci avait été présenté (pour l'essentiel) devant CWG il y a quelques années, mais avait été retiré parce que cela semblait aider à l'atteinte du consensus. On le revoit maintenant que les contrats font partie du langage.

Le modèle est intéressant : on sollicite d'abord les préconditions de l'appel du type statiquement connu puis ceux de l'appel du type dynamiquement découvert, puis en sortie les postconditions de l'appel du type dynamiquement découvert suivies de celles de l'appel du type statiquement connu.

Par exemple :

struct X1 { virtual void f() pre(a) post(b); };
struct X2 { virtual void f() pre(c) post(d); };
struct Y : X1 { void f() override pre(e) post(f); };
struct Z : Y, X2 { void f() override pre(g) post(h); };
void t() {
  Z z;
  z.f(); // asserts g, h
  static_cast<Y*>(&z)->f(); // asserts e, g, h, f
  X1 &x1ref = z;
  X2 &x2ref = z;
  x1ref.f(); // asserts a, g, h, b
  x2ref.f(); // asserts c, g, h, d
  x1ref.X1::f(); // asserts a, b
  void (X1::*pmf)() = &X1::f;
  (x1ref.*pmf)(); // asserts g, h
}

Timur Doumler souligne que l'exemple avec héritage multiple est important parce que dans un tel cas, C++ diffère d'autres langages comme Eiffel qui ont aussi des contrats. Jason Merrill suggère d'ajouter un exemple avec une Splice, alors on obtient :

struct X1 { virtual void f() pre(a) post(b); };
struct X2 { virtual void f() pre(c) post(d); };
struct Y : X1 { void f() override pre(e) post(f); };
struct Z : Y, X2 { void f() override pre(g) post(h); };
void t() {
  Z z;
  z.f(); // asserts g, h
  static_cast<Y*>(&z)->f(); // asserts e, g, h, f
  X1 &x1ref = z;
  X2 &x2ref = z;
  x1ref.f(); // asserts a, g, h, b
  x1ref.[:^^X1::f:]();  // asserts a, g, h, b
  x2ref.f(); // asserts c, g, h, d
  x1ref.X1::f(); // asserts a, b
  void (X1::*pmf)() = &X1::f;
  (x1ref.*pmf)(); // asserts g, h
}

On est satisfaits avec ceci. On ajoute une feature test macro. Ready.

(pause du matin; nos pauses sont à 4 h 15 heure de Montréal ce qui correspond à peu près au moment où Pauline a besoin d'aller à l'extérieur puis de manger une bouchée, alors heureusement son horaire n'est pas trop bouleversé!)

P2796 – Type-aware allocation and deallocation functions

On examine une version mise à jour de la proposition. La gestion du std::type_identity<T> dans une type-aware allocation function a été resserrée. On essaie de voir si la nouvelle expression permet à un compilateur d'éviter de se retrouver dans une situation type-dependent.

Le texte des fonctions d'allocation est pas mal, mais l'auteur est préoccupé par son écriture du texte sur les fonctions de déallocation (il faut bien définir les règles de mise en correspondance avec la fonction d'allocation correspondante). Pour réduire la répétition il a déplacé une section mais est inquiet des conséquences. On examine le tout avec lui. On pense que l'idée de perfect matching function d'une autre proposition aidera à recoller les morceaux. Il y a quelques enjeux ici et on essaie de choisir la moins pire des options. Jens Maurer note que [expr.new] est trop chargé de trucs qui devraient être ailleurs, mais ça dépasse un peu ce qu'on peut demander à cette proposition.

On ne finira probablement pas celle-là cette semaine.

P4101 – Consteval-only Values for C++26

C'est une proposition qui visait C++26 mais n'est pas arrivée à ses fins à temps.

L'idée de consteval-only type s'en va; celle de consteval-only value prend l'espace sémantique qui s'en trouve libéré. On a donc désormais des immediate objects en plus des immediate functions.

On travaille un peu le texte. Il est en général bien écrit (il y a des sons de plaisir dans la salle).

On a cet exemple :

consteval int plus1(int x) { return x + 1; }
template <auto V> struct C { };

auto a = plus1; // error: immediate object not associated with constexpr variable
constexpr auto b = plus1; // ok
auto c = C<plus1>(); // ok

auto d = ^^int; // error: immediate object not associated with constexpr variable
auto e = C<^^char>(); // ok

Avec la réflexivité, le mécanisme d'immediate escalation et ces nouvelles valeurs consteval-only, le texte qui définit ce qu'est une constant expression fond à vue d'oeil. On a toutefois immediate constant expression qui apparaît, suivi de immediate escalation.

Quelques exemples :

consteval int id(int x) { return x; }
template <auto F>
constexpr auto apply_to(int i) { return F(i); }

auto p = &apply_to<id>; // error: immediate function because F(i)
                        // is not a constant expression

... puis :

consteval std::meta::info refl() { return ^^int; }
template <auto F>
constexpr void ex() {
  auto x = F();
}

auto p = &ex<refl>; // error: immediate function because F()
                    // is an immediate constant expression

... puis :

std::meta::info r;
void normal() {
  r == r; // ok
  r == ^^int; // error
}

Davis Herring fait remarquer que la définition de core constant expression est désormais simplement « A core constant expression is a constant expression unless it is a prvalue whose result object ([basic.lval]) has a constituent value that is an invalid pointer value ([basic.compound]) or is indeterminate or erroneous ([basic.indet]). »

Effet de bord intéressant : std::exception::what() n'a plus le requis d'être consteval avec cette simplification. La salle est fortement sympathique aux effets simplificateurs de ce que contient le texte de cette proposition.

Un ptr_tag transporté par un void* peut constituer une invalid pointer value à la compilation. C'est... novateur.

(c'est presque prêt, mais c'est aussi l'heure du dîner; je m'occupe un peu de ma famille puis on reprend les travaux)

Jens Maurer fait un résumé des travaux du matin pour nous situer en vue de ce dernier après-midi de travail de la semaine, puis on continue la plus récente proposition.

Brian Bi se demande si les changements proposés au modèle peuvent impacter SFINAE (de manière inattendue). On discute des facettes de ce problème, mais on semble pense que la situation est gérable. Hubert Tong se demande pour sa part si le modèle proposé peut imposer une évaluation supplémentaire des expressions, mais cette préoccupation ne semble pas partagée par les autres implémenteurs dans la salle. On discute aussi des interactions avec define_aggregate() (toujours aussi épeurant).

Ready. Faut toutefois que LWG puisse le voir.

P2414 – Pointer lifetime-end zap proposed solutions

Le sous-titre est « Atomics and volatile ». On discute de tours de passe-passe avec l'équivalent moral d'un reinterpret_cast de manière ne permettant pas l'exposition de l'adresse (fictive) à du code réellement exécuté. Ces manoeuvres visent à représenter les atomiques par des pointeurs vers leurs représentations, et le permettre ailleurs que dans le contexte demandé brise des tas d'optimisations.

Ready.

P3670 – Pack Indexing for Template Names

Les enjeux soulevés au sujet de cette proposition plus tôt cette semaine semblent avoir été traités, mais on fait un grand tour de la proposition parce que ses ramifications sont nombreuses.

Ready.

P3367 – constexpr coroutines

Une autre proposition déjà vue cette semaine et dont on examine les retouches (phrasé, choix des termes techniques, structure générale de la prose). La proposition parle de « entering a coroutine » car certains se questionnent sur le sens formel de « entering », mais on trouve des cas ailleurs dans le standard (ça reste un peu informel).

(je dois quitter pendant l'examen de cette proposition)

Je ne suis pas revenu à temps pour terminer la journée de travail alors il me manque environ 90 minutes. Je fais un somme de trois heures environ, puis je vais sur le Wiki de CWG et je constate qu'on a discuté de :

Je prends le temps de lire sur ce qui s'est dit (merci à Jason Merrill d'avoir pris de bonnes notes!), puis je commence ma lecture des propositions soumises au vote tantôt par LWG pour savoir où je me positionne face à elles.

Jour 5 – 13 juin 2026

Nina Ranns nous accueille. On a une chic vue sur le devant de la scène! On offre des chocolats aux gens qui ont joué le rôle de scribes cette semaine (bonne idée!)

Rapports des groupes d'études

ABI Group : pas de rapport à offrir.

Admin Group : on a eu 187 participant(e)s, avec une légère najorité en personne. Le Canada offre la quatrième plus grande participation après les États-Unis, la Grande Bretagne et UNMZ (pas sûr du pays). On fait le tour des dates des prochains mailings.

SG1: Concurrency and Parallelism Study Group : travail sur les atomiques et la compatibilité avec C, pour que les facilités de bas niveau correspondent mieux d'un langage à l'autre. La durée de vue fut un sujet chaud. Une première ronde de travaux sur les senders/ receivers. Les files d'attente concurrentes. Appui unanime aux primitives de synchronisation asynchrones (c'est rare!)

SG2: Modules Study Group : inactif cette semaine

SG3: File System Study Group : inactif cette semaine

SG4: Networking Study Group : le plan était de se rencontrer mais l'auteur de la principale proposition souhaitait attendre à la prochaine rencontre.

SG5: Transactional Memory : inactif cette semaine

SG6: Numerics : nous avions un bon groupe et nous sommes rencontrés deux jours durant pour voir dix propositions, dont trois ont été relayés à des groupes de travail. Une amélioration du traitement des nombres à virgule flottante dans le texte du standard suit son cours, et les unités de mesure progressent bien. On souhaite avoir l'annexe F pour « floating point »

SG7: Reflection : inactif cette semaine

SG8: Concepts : inactif cette semaine

SG9: Ranges : nous nous sommes rencontrés et nous avons même manqué de temps. Des neufs propositions couvertes, nous en avons relayé huit! Nous avons aussi élargi notre mandat pour couvrir le cas des « non-iterator ranges »

SG10: Feature Test : inactif cette semaine

SG12: Undefined and Unspecified Behavior : inactif cette semaine

SG13: I/O : inactif cette semaine

SG14: Low Latency : inactif cette semaine, mais on travaille chaque mois sur la proposition de Patrice Roy et sur les exceptions pour systèmes embarqués. Les interactions avec Networking et les exécuteurs nous occuperont au cours des prochains mois. Certains aspects portant sur de la programmation hétérogène risquent de s'ajouter à notre plan de travail sous peu

SG15: Tooling : quelques travaux cette semaine

SG16: Unicode : inactif cette semaine mais on progresse en ligne

SG17: EWG Incubator : inactif cette semaine

SG18: LEWG Incubator : nous avons eu un bon groupe et nous avons couvert cinq propositions! Entre autres, copy_on_write a été relayé à LEWG, et nous avons couvert des propositions de synchronisation relayées à des groupes de travail

SG19: Machine Learning : inactif cette semaine, mais on travaille chaque mois. Nos gros sujets sont les statistiques et le Machine Learning. Nous travaillons dans une acception plus globale de C++ et de l'intelligence artificielle contemporaine, C++ étant le substrat sur lequel le reste du monde de l'IA contemporaine est construit.

SG20: Education : nous nous sommes rencontrés. 15 sujets d'enseignement sont en cours de développement. On essaie d'encourager les universités de débuter leur enseignement avec C++ plutôt que C pour éviter la confusion. Nous avons examiné la proposition sur les unités de mesure qui contient une solide section décrivant l'enseignement de ce sujet. Nous nous sommes intéressés à l'enseignement de la réflexivité et à l'accueil des débutant(e)s.

SG21: Contracts : inactif cette semaine

SG22: C/C++ Liason : inactif cette semaine mais on progresse en ligne. Le Chair fait le tour des nouveautés du côté de WG14

SG23: Safety and Security : rencontre d'une pleine journée. Nous avons discuté de Profiles, des préconditions d'algorithmes sur des algorithmes tels que std::copy(), du profil d'initialisation.

Rapports des groupes de travail

EWG : nous nous sommes rencontrés trois jours, plus une rencontre conjointe avec LEWG. L'un des jours portait sur les contrats et a mis au jour un plan de progression de de côté.

LEWG : grosse semaine avec plus de 35 propositions. Quelques correctifs pour format(), constant_wrapper, error_code... Nous avons discuté de politiques. Des raffinements tels que cstring_view, basic_fixed_string, embed, #depend, etc. Plusieurs ranges, et avec EWG nous avons discuté de types précis aux bits près pour que is_integral_v<_Bitint(N)>`soit true

CWG : grosse semaine, et pour la première fois depuis longtemps nous avons une proposition de plus soumise au vote que LWG. Notez que nous allons ajouter une annexe sur le UB et le IFNDR au standard pour nous aider à réduire ces irritants, par exemple à l'aide des Profiles. Nous allons donc demander aux autrices et aux auteurs d'examiner, dès la prochaine rencontre, tout changement requis à ces annexes. Notez aussi que plusieurs des votes spont proposés à titre de DR. La proposition 16 a généré du trafic en ligne (contrats sur les fonctions virtuelles) alors je veux signaler, par transparence, sa présence ici. Les coroutines constexpr ont été retirées car LWG n'a pas fini de les examiner.

LWG : semaine intéressante et productive où nous avons fermé quelques Library Issues. La plupart des propositions traitées sont proposées pour vote aujourd'hui, et (chose rare!) nous avons eu quelques décisions partagées demandant au Chair de prendre position (la plupart du temps, LWG est unanime). Les votes 5 et 7 devraient être des DR; j'aimerais les ajuster en conséquence aujourd'hui, sinon ce sera fait au Brésil (il y a objection dans la salle pour les marquer comme DR aujourd'hui).

Votes proposés par CWG

Les votes amenés par CWG cette semaine sont les suivants.

1. Accept as Defect Reports and apply the proposed resolutions of all issues in P4271R0 (Core Language Working Group "ready" Issues for the June, 2026 meeting) to the C++ Working Paper.

Unanime

2. Apply the changes in P3596R3 (Undefined Behavior and IFNDR Annexes) to the C++ Working Paper.

Vote demandé. Consensus pour

3. Apply the changes in P2287R6 (Designated-initializers for Base Classes) to the C++ Working Paper.

Unanime

4. Accept as a Defect Report and apply the changes in P3899R3 (Clarify the behavior of floating-point overflow) to the C++ Working Paper.

Unanime

5. Apply the changes in P3668R4 (Defaulting Postfix Increment and Decrement Operations) to the C++ Working Paper.

Quelqu'un demande si une étude menant à la disparition de l'étrange syntaxe avec un paramètre int « fantôme » a été tenue. Le Chair de EWG dit ne pas avoir souvenir d'une telle discussion. L'auteur dit que la discussion a eu lieu à Sofia, mais les alternatives explorées ne furent pas satisfaisantes.

Vote demandé. Consensus pour

6. Apply the changes in P2953R5 (Adding restrictions to defaulted assignment operator functions) to the C++ Working Paper.

Unanime

7. Accept as a Defect Report and apply the changes in P2434R5 (Nondeterministic pointer provenance) to the C++ Working Paper.

Unanime

8. Accept as a Defect Report and apply the changes in P3347R6 (Invalid Pointer Operations) to the C++ Working Paper.

Unanime

9. Accept as a Defect Report and apply the changes in P3658R1 (Adjust identifier following new Unicode recommendations) to the C++ Working Paper.

Unanime

10. Accept as a Defect Report and apply the changes in P3950R1 (return_value & return_void Are Not Mutually Exclusive) to the C++ Working Paper.

Unanime

11. Accept as a Defect Report and apply the changes in P3733R1 (More named universal character escapes) to the C++ Working Paper.

Unanime

12. Accept as a Defect Report and apply the changes in P3847R1 (Lexical order for lambdas) to the C++ Working Paper.

Unanime

13. Accept as a Defect Report and apply the changes in P2243R0 (Language linkage for templates) to the C++ Working Paper.

Unanime

14. Apply the changes in P3424R2 (Deallocation Functions with Throwing Exception Specification Are Ill-formed) to the C++ Working Paper.

Unanime

15. Apply the changes in P3822R2 (Conditional noexcept specifiers in compound requirements) to the C++ Working Paper.

Unanime

16. Apply the changes in P3097R3 (Contracts for C++: Virtual functions) to the C++ Working Paper.

Quelqu'un signale que les préoccupations autour de ce mécanisme n'ont pas été adressées, et demande de retenir le vote jusqu'à la prochaine rencontre pour permettre des propositions de réplique. Le Chair indique que cette option existait depuis plus de huit mois et que les rebuffades n'ont pas été écrites.

Vote demandé. Consensus pour

17. Accept as a Defect Report and apply Apply the changes in P4101R1 (Consteval-only Values for C++26) to the C++ Working Paper.

Unanime

18. Accept as a Defect Report and apply Apply the changes in P2414R12 (Pointer lifetime-end zap proposed solutions) to the C++ Working Paper.

Unanime

19. Apply the changes in P3670R4 (Pack Indexing for Template Names) to the C++ Working Paper.

Unanime

20. Apply the changes in P3540R3 (#embed offset parameter) to the C++ Working Paper.

Unanime

Votes proposés par LWG

Les votes amenés par LWG cette semaine sont les suivants. Je laisse quelques commentaires pour les intéressé(e)s, mais notez que je ne fais qu'une lecture rapide et je n'ai pas participé aux discussions alors il se peut que des détails subtils mais importants m'échappent. Aussi, mes commentaires somt écrits quelques heures avant les votes.

01. Apply the changes in P4258R0 (C++ Standard Library Ready Issues to be moved in Brno, Jun. 2026) to the C++ working paper.

Unanime

02. Apply the changes in P3319R6 (Add an iota object for simd (and more)) to the C++ working paper.

Une version de std::iota() pour std::simd sous forme d'un objet. Ça me semble vraiment chouette.

Unanime

03. Apply the changes in P3798R1 (The unexpected in std::expected) to the C++ working paper.

Mineur mais ne fait pas de mal : ajouter un accesseur e.has_error() qui équivaut à !e.has_value() pour alléger le code client.

Unanime

04. Apply the changes in P3052R2 (view_interface::at()) to the C++ working paper.

Mineur, mais permet d'utiliser at() sur des views pour lever une exception dans le cas d'un débordement. Tant que ça ne coûte pas plus cher, ça aidera peut-être des gens.

Unanime

05. Apply the changes in P4206R0 (Revert string support in std::constant_wrapper) to the C++ working paper.

Ça semble raisonnable : les avantages ne semblent pas suffisants pour les inconvénients et il y a des alternatives.

Quelqu'un demande si la proposition contient une entrée pour l'annexe C. Le Chair dit non. La préoccupation est que le standard C++26 contient la version actuelle et que ceci est un Breaking Change. On peut toutefois ajouter cette entrée a posteriori

Unanime

06. Apply the changes in P3395R6 (Fix encoding issues and add a formatter for std::error_code) to the C++ working paper.

Pouvoir utiliser normalement un std::error_code avec std::format() et std::print(). Excellente idée.

Unanime

07. Apply the changes in P3505R4 (Fix the default floating-point representation in std::format) to the C++ working paper.

Oui, on en a besoin.

Quelqu'un demande si la proposition contient une entrée pour l'annexe C. Le Chair dit non. La préoccupation est que le standard C++26 contient la version actuelle et que ceci est un Breaking Change. On peut toutefois ajouter cette entrée a posteriori

Unanime

08. Apply the changes in P3154R3 (Deprecating signed character types in iostreams) to the C++ working paper.

Ok, je comprends et je ne voterai pas contre, mais ça adonne que j'ai un exemple qui fait précisément ce que nous allons déprécier par ce vote dans le plus récent chapitre envoyé à mon éditeur pour mon prochain livre! Je l'ai averti et je vais retoucher l'implémentation en conséquence. Heureusement que je  l'ai vu avant que le livre ne soit publié!

Unanime

09. Apply the changes in P3428R4 (Hazard Pointer Batches) to the C++ working paper.

C'est une optimisation (c'est plus rapide de créer en bloc plusieurs hazard pointers que de les créer séparément). Ok.

Unanime

10. Apply the changes in P3248R5 (Require [u]intptr_t) to the C++ working paper.

Les types intptr_t et uintptr_t ne sont pas présents de manière portable avec toutes les implémentations, mais cette proposition est à l'effet de les rendre obligatoires. J'aimerais beaucoup que ça passe, mais il se peut qu'il y ait un vote provenant de gens sur des plateformes où ceci n'est pas une option. Ça semble avoir été préparé en collaboration avec des experts de WG14, le comité de C, et c'est tant mieux.

Unanime

11. Apply the changes in P3793R2 (Better shifting) to the C++ working paper.

Des fonctions std::shl() et std::shr() qui opèrent sur les bits d'un entier, qui sont constexpr, évitent les problèmes de priorité étrange des opérateurs pour operator<< et operator>>, et évitent des cas limites qui prêtent à confusion. Ça me semble pertinent. 

Unanime

12. Apply the changes in P3242R4 (Copy and fill for mdspan) to the C++ working paper.

Je pensais qu'on les avait déjà, mais je n'ai pas beaucoup joué avec std::mdspan encore.

Unanime

13. Apply the changes in P3692R4 (How to Avoid OOTA Without Really Trying) to the C++ working paper.

Celui-ci est subtil, mais n'apporte que deux notes non-normatives. L'idée est que produire des valeurs Out of Thin Air dans du code concurrent peut générer des conditions de course qui n'étaient pas dans le texte du code source original. C'est un texte très intéressant.

Unanime

14. Apply the changes in P3104R6 (Bit permutations) to the C++ working paper.

Quelques ajouts utiles à <bit>.

Unanime

15. Apply the changes in P3772R2 (std::simd overloads for bit permutations) to the C++ working paper.

Un compagnon simd à P3104.

Unanime

16. Apply the changes in P3091R6 (Better Lookups for map, unordered_map, and flat_map) to the C++ working paper.

J'aime bien : l'ajout de fonctions membres lookup() retournant des std::optional<V> où V est le type des valeurs. Ça mène à du code client élégant et efficace.

Unanime

17. Apply the changes in P3125R6 (constexpr pointer tagging) to the C++ working paper.

C'est amusant ça : un type permettant de faire des masques de bits de manière constexpr sur des pointeurs en utilisant les bits les plus faibles (qui ne sont habituellement pas utilisés pour raisons d'alignement du pointeur... On ne parle pas du pointé ici).

Vote demandé. Consensus pour

18. Apply the changes in P2019R9 (Thread attributes) to the C++ working paper.

C'est la suite d'une proposition que j'ai moi-même porté il y a quelques années. C'est pas mal, et je ne voterai pas contre, mais un problème de fond demeure car on ne peut pas rapporter un problème sans lever une exception.

Vote demandé. Consensus pour.

19. Apply the changes in P3785R1 (Library Wording Changes for Defaulted Postfix Increment and Decrement Operations) to the C++ working paper.

On a vu la contrepartie Core chez CWG.

Unanime

Votes proposés par WG21

Les votes pour WG21 sont les suivants : rien cette semaine

Autres rapports

On remercie les scribes et on les applaudit. On remercie Hana Dusíková, notre hôte, et on lui souhaite bon anniversaire.

Direction group : c'est un groupe avec direction rotative. Daveed Vandevoorde est Chair en ce moment.

Les prochaines rencontres seront à Búzios (Rio de Janeiro, Brésil), N5021, le 16 novembre 2026. Les suivantes seraient, dans l'ordre : Instanbul, Sofia, Budapest, Kona, Madrid et Crete. Seuls Búzios et Istanbul sont confirmés pour le moment

On remercie les participantes et les participants, en particulier les Chairs. On remercie les membres de nos familles qui nous permettent de faire ce travail, puis on ajourne.

Belle et grosse semaine!


Valid HTML 1.0 Transitional

CSS Valide !