À propos de WG21, St-Louis 2024 (juin)

Je participe à cette rencontre à distance, mais je serai moins présent et actif qu'à l'habitude car c'est une grosse semaine sur le plan personnel (Fête Nationale du Québec, ce qui est difficile à escamoter avec des enfants; anniversaire de mariage; rendez-vous médicaux; événement pour le 80e anniversaire de naissance de mon chic papa Réal, etc.).

La rencontre de cette semaine se tenant à St-Louis, le décalage horaire est minime (une heure à peine), ce qui permettra de maintenir un rythme de vie raisonnable malgré tout.

Les principaux thèmes de la rencontre sont la progression des travaux pour C++ 26, en particulier les Senders/Receivers, la réflexivité statique et – surtout – les contrats. Je devrais passer ma semaine chez CWG comme à mon habitude parce que les travaux sur certains dossiers de fond (constexpr et les Structured Bindings; l'idée de Trivially Relocatable; Less Transient constexpr Allocation; les Expansion Statements; Structured Bindings can introduce a Pack; etc.) m'intéressent beaucoup.

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 – 24 juin 2024

Je suis arrivé parmi les premiers à la plénière du matin. C'est tranquille chez moi, mais il y a eu de nombreuses pannes de courant ce matin (fortes pluies dehors) alors je ne sais pas quel genre de présence je pourrai offrir.

John Spicer fait l'accueil. Bill Seymour, notre hôte, offre quelques mots, et explique entre autres que le IEC a été conçu en ces lieux. John Spicer explique ensuite les règles de la rencontre, le code de conduite, les procédures de vote, etc. Nina Ranns donne un excellent rappel du rôle et du comportement attendu de chaque participante et de chaque participant. On fait ensuite le tour des nouveaux participants, ce qui inclut... Andrei Alexandrescu, ce qui nous fait bien rire!

Herb Sutter vérifie les NB présents; on en compte 18, pas mal, incluant le Kazakhstan et l'Inde!

Brève pause, puis on passe aux rencontres de groupes d'étude et de groupes de travail. Je suis (virtuellement) chez CWG. On règles les inévitables irritants techniques (Jens Maurer est remarquable dans son travail) et on procède.

P0562R2 Trailing Commas in Base-clauses and Ctor-initializers

Alan Talbot est présent en personne et présente cette proposition. C'est une proposition qui remonte à plusieurs années! L'idée est de permettre à une liste de classes parents et d'initialiseurs de variables membres de terminer par une virgule, comme on le permet ailleurs (macros, énumérations).

Roger Orr demande si on couvre les listes d'initialisations avec la proposition. Alan Talbot dit qu'il est ouvert mais que ce serait une autre proposition, pas celle-ci. La proposition sur la table est un très léger ajustement à la grammaire (l'ajout de huit caractères au total!), et vise à simplifier l'entretien du code pour des millions de personnes.

On l'enverra au vote samedi.

P2686R3 constexpr structured bindings and references to constexpr variables

Corentin Jabot et Brian Bi co-présentent. Il y a un sérieux effort dans cette proposition de formaliser ce que signifie être constexpr : à partir de quel moment cela s'avère, ce que ça signifie pour des références, ce que ça signifie pour des variables static, etc. On y trouve des idées comme ce que signifie constant-initialized, potentially constant, constexpr-referenceable, constexpr-representable at point P, etc.

Brian Bi explique que les Structured Bindings ne sont pas techniquement des références, alors les exprimer en contexte constexpr requiert la description de ce qui se produit quand on les utilise, avec de nouveaux mots. Un chic exemple :

#include <tuple>
struct A {
   virtual int g() const;
};
void f(std::tuple<A&> a) {
   auto [r] = a;
   static_assert(r.g() >= 0); // error: dynamic type is constexpr-unknown
}

Tout ce travail de fond mène, éventuellement, à la mise à jour terminologique des Structured Bindings qui vise à couvrir à la fois constexpr et constinit. Le capacité d'utiliser un objet dans un contexte constexpr devient usable at point P désormais avec cette proposition. Exemple :

struct A {
   int* const & r;
};
void f(int x) {
   constexpr A a = { &x };
   static_assert(a.r == &x); // OK
   [&] {
      static_assert(a.r != nullptr); // error: a.r is not usable in
                                     // constant expressions at this point
   }();
}

Autre exemple intéressant :

struct pixel {
   int x, y;
};
constexpr pixel ur = { 1294, 1024 }; // OK
constexpr pixel origin; // error: initializer missing
namespace N {
   void f() {
      int x;
      constexpr int &ar = x; // OK
      static constexpr int &sr = x; // error: x is not
                                    // constexpr-representable at the point
                                    // indicated below
   }
// immediate scope here is that of N
}

Jason Merrill fait remarquer que dans l'exemple suivant, le cas de rtt est un peu triste :

void f() {
   int ax; // ax is not constant-initialized
   thread_local int tx; // tx is constant-initialized
   static int sx; // sx is constant-initialized
   static int &rss = sx; // rss is constant-initialized
   static int &rst = tx; // rst is not constant-initialized
   static int &rsa = ax; // rsa is not constant-initialized
   thread_local int &rts = sx; // rts is constant-initialized
   thread_local int &rtt = tx; // rtt is not constant-initialized
   thread_local int &rta = ax; // rta is not constant-initialized
   int &ras = sx; // ras is constant-initialized
   int &rat = tx; // rat is not constant-initialized
   int &raa = ax; // raa is constant-initialized
}

Brian Bi est d'accord, mais c'est un enjeu préexistant et plus complexe que les autres alors il n'est pas allé là.

Hubert Tong fait remarquer que pour la définition de constituent values, [j'ai manqué un bout pour des raisons familiales]. L'enjeu semble être qu'on a une définition qui se veut récursive mais pour laquelle il y a une forme de redondance superflue. MM précise qu'une partie de l'enjeu est qu'une référence n'est pas un objet. Brian Bi explique que la subtilité est qu'un objet a une existence indépendante de celle de la variable qui le nomme. Le passage sous discussion est la première puce de :

« The constituent values and constituent references of a variable x are defined as follows:

[...] »

J'ai dû m'arrêter pour l'après-midi dû à des obligations familiales; selon le Wiki de CWG, les dossiers suivants ont été abordés :

Suite de P2686

P3340 A Consistent Grammar for Sequences

P1061 Structured Bindings can introduce a Pack

P3144 Deprecate Delete of a Pointer to an Incomplete Type

Quelques Core Issues :

Jour 1 – 25 juin 2024

C'est mon anniversaire de mariage aujourd'hui mais mon amoureuse et moi sommes tous deux débordés de travail alors on sera affairés (on aura du temps ensemble la semaine prochaine, et on avait un spectacle la semaine passée... La vie).

J'ai manqué la matinée à St-Louis, devant aller à Montréal pour un rendez-vous relativement urgent avec un de nos animaux. Sur la base du Wiki de CWG, les sujets du matin furent :

P2841 Concept and variable-template template-parameters (qui semble vraiment intéressant)

P2963 Ordering of constraints involving fold expressions

Quelques Core Issues :

Cet après-midi, je vais commencer par aller à SG23 car Sean Baxter (auteur de Circle) donnera une présentation devant le comité sur le Secure C++ auquel il travaille depuis un certain temps, et c'est un peu ma faute s'il fait cela aujourd'hui alors il me semble important que j'aille assister à sa présentation.

La présentation est fort intéressante, et utilise un mot clé safe qui se comporte un peu comme noexcept sur le plan syntaxique et comme const sur le plan des garanties transitives. Il utilise ^ pour des références au sens de Rust, et rel pour provoquer une relocalisation (un destructive move) de même que drp pour faire un release sur un borrow (destructeur puis invalidation). Il montre à la fois plusieurs exemples et comment il a réalisé son implémentation. Le durée de vie relative des variables empruntées est inscrite dans le système de types.

On a des questions sur la capacité d'affecter nullptr à un unique_ptr<T> (tu ne peux pas dans un contexte safe). Aussi, on peut emprunter un int ce qui est comme un passage par référence mais rend l'original invalide (erroneous behavior?) suivant l'appel

Un truc qui ressort de tout ça est que si on souhaite adopter ce modèle inspiré de Rust, il faudra changer une grande partie de la bibliothèque standard. Un truc comme std::swap() qui mute deux paramètre doit être marqué unsafe (mais peut être appelé d'un équivalent safe qui validerait la durée de vie des paramètres). Sean Baxter explique que unsafe ne signifie pas « dangereux » mais bien « sous la responsabilité de la personne qui programme ».

On se demande si on veut encourager ces travaux, y investir temps et efforts, car ça va demander des changements considérables à la bibliothèque standard. Sean Baxter propose une approche incrémentale qui pourrait faire du sens, tout en préservant ce que C++ a d'avantageux à offrir.

Un vote se tient et nous avons un consensus très fort pour la poursuite des travaux. Bonne chose!

J'ai dû quitter par la suite (les discussions chez SG23 se sont poursuivies jusqu'à la fin de la journée, toujours à propos du Borrow Checker et de son intégration éventuelle à C++).

Chez CWG, durant l'après-midi, les dossiers traités furent (sur la base du Wiki) :

P2686R3 constexpr structured bindings and references to constexpr variables (ça semble avoir occupé la plus grande part de l'après-midi)

LWG4064 pour le cas où on a :

alignas(int) char buf[sizeof(int)];
int n = 3;
int *p = static_cast<int *>(memcpy(buf, &n, sizeof n));

... et on se demande si std::launder() est nécessaire. Il y a des subtilités ici...

P2434 Nondeterministic pointer provenance

P1494 Partial Program Correctness

J'ai manqué des trucs vraiment intéressants! Hé la la...

Jour 2 – 26 juin 2024

Il manque des joueurs aujourd'hui dû aux discussions (rudes mais importantes) sur les contrats. On procède avec des Core Issues dans les circonstances

Core Issue 2904 Introducing template-names

Il semble y avoir un enjeu grammatical où l'intention n'est pas bien portée par la grammaire, avec les noms des templates qui sont moins bien situés grammaticalement que les noms d'autres trucs comme les énumérations par exemple. Cela bloque certains usages légitimes de ces noms. Entre autres, un concept-name devient aussi un template-name. Christof Meerwald fait remarquer qu'il peut y avoir de la confusion entre concept-name et concept-identifier. Hubert Tong signale qu'il y a un enjeu avec la formulation de l'introduction du texte, mais ça semble préexistant (on travaille un peu la formule). Hubert Tong remarque qu'avec le texte proposé on pourrait escamoter le auto après un nom de concept pour définir un type, alors il y a un petit bogue de grammaire (ça pourrait mener à un irritant du type Most Vexing Parse).

Il semble y avoir deux directions en lien avec les function-templates (s'agit-il de template-names ou pas?). Brian Bi pense que le côté un peu obscur du texte tient au fait qu'il a été écrit par plusieurs personnes sur une longue période de temps. Jason Merrill pense que l'idée de template-name vise la désambiguation du symbole < suivant un nom.

Core Issue 2815 Overload resolution for references/pointers to noexcept functions

L'exemple motivateur est :

void f() noexcept {}

void g(void (*)() noexcept) {}
void g(void (&)()) {}

int main() {
  g(f);     // error: ambiguous
}
// mais...

void f() noexcept {}

void g(void (*)()) {} 
void g(void (&)()) {}      // #1

int main() {
  g(f);    // OK, calls #1
}

C'est embêtant. C'est parce qu'il y a une identity conversion qui s'applique dans le cas des références... Brian Bi dit ne pas avoir soumis de résolution parce que les résolutions « évidentes » brisent du code valide. Jason Merrill pense que ça devrait être ambigu (si on retire le noexcept, ce l'est déjà). La section [over.ics.scs] indique les catégories de transformations possibles et on constate que la famille à laquelle appartient les conversions de pointeurs de fonctions peut être la raison pour laquelle nous appliquons des règles douloureuses ici.

Une fois qu'on a une piste, Brian Bi prend sur lui de proposer une résolution. P0.

Core Issue 2905 Value-dependence of noexcept-expression

Le problème signalé est que les expressions noexcept suivantes ne sont pas value-dependent mais devraient l'être :

template <typename T>
  void f() {
    noexcept(static_cast<int>(T{}));
    noexcept(typeid(*T{}));
    noexcept(delete T{});
  }

Une motivation est que la levée d'exception dépend du constructeur par défaut de T. Jens Maurer propose une reformulation... On déplace noexcept(expr) de l'endroit où cette expression loge vers un lieu qui montre que ça peut effectivement être value-dependent. On vise Tentatively Ready pour la prochaine rencontre.

Core Issue 2728 Evaluation of conversions in a delete-expression

On a cette vieille phrase : « The cast-expression in a delete-expression shall be evaluated exactly once » qui est totalement incorrecte (on ne peut pas supposer qu'une expression ne sera évaluée qu'une fois – ça pourrait par exemple être zéro! – et le cast-expression n'est pas le bon niveau d'abstraction.

La proposition de correctif est significativement meilleure. Tentatively Ready pour samedi

Core Issue 2814 Alignment requirement of incomplete class type

L'exemple est :

struct X;       // declared, but not defined

int i;
X* p = static_cast<X*>(static_cast<void*>(&i));

On pense que ça devrait être permis (c'est un changement de direction par rapport à une position du passé) outre quelques cas limites. Jason Merrill signale que le résultat ne peut pas être correctement aligné en général. Brian Bi signale que le texte couvre correctement ce cas.

Core Issue 2818 Use of predefined reserved identifiers

Le problème découle de l'interdiction d'utiliser __ dans un identifiant du code client... mais les Feature Test Macros ont cette forme, alors il faut une exception pour ce cas.

La résolution convient. Tentatively Ready pour samedi.

Core Issue 2819 Cast from null pointer value in a constant expression

On a besoin d'un traitement particulier pour le cas void* vers T* quand le void* est nul dans une expression constante car le texte ne le permettait pas, ce qui est clairement un irritant. Ce ne sera pas un DR par contre. Tentatively Ready pour samedi

Core Issue 2836 Conversion rank of long double and extended floating-point types

L'exemple est :

auto f(long double x, std::float64_t y) {
  return x + y;
}

... quel est le type de f()? On a découvert que C et C++ diffèrent, et de manière intentionnelle selon EWG. Ce n'est un enjeu que quand les types ont la même taille (sans cette situation, les règles sont les mêmes). On veut mettre un exemple dans l'annexe C, mais... on ne peut pas écrire le nom du type C en C++ et l'inverse est aussi vrai, alors il est difficile de donner un exemple raisonnable! On y va avec de la prose, puis on élargit un peu la formulation car on s'attend, éventuellement, à d'autres découvertes du genre. Tentatively Ready pour samedi

Core Issue 2858 Declarative nested-name-specifiers and pack-index-specifiers

C'est un petit enjeu grammatical (on a oublié de changer le terme decltype specifier dans la prose pour computed-type-specifier). Pas un DR, car le changement à la source de celle-ci remonte à Tokyo, mais Tentatively Ready pour samedi.

Core Issue 2859 Value-initialization with multiple default constructors

L'enjeu est une confusion entre avoir un constructeur d'une certaine forme et s'en servir pour quelque chose, surtout depuis qu'on a des contraintes exprimées sous forme de concepts et de clauses requires. Le texte préexistant n'est pas adapté pour cette nouvelle réalité. Faut préciser vacuous initialization et zero-initialization en ces nouveaux termes.

On y reviendra.

Core Issue 2861 dynamic_cast on bad pointer value

Le texte existant couvre bien les conversions valides et le cas nullptr, mais moins bien les pointeurs incorrects comme ceux pointant vers un type effectif différent du type apparent (par exemple parce que le code a fait des bêtises avec reinterpret_cast au préalable). On veut assurément du comportement indéfini et ça vaut la peine de l'écrire dans ce cas (on essaie de rendre ces cas plus explicites après tout).

On y reviendra.

Core Issue 2862 Unclear boundaries of template declarations

On a des cas qui ne sont pas clairs. Par exemple :

template <int>
  struct S {} v;
// declaration of a class template? declaration of a variable template? neither? Implementations uniformly reject.
template<class T>
  typedef struct C F;

Clarifier l'intention ici demande pas mal de texte. On veut que v soit ambigu (déclare les deux), mais que F déclare un variable template. La résolution propose aussi :

template<typename T> struct A {
   template<typename U> struct B;
  template<typename U> struct B<U*> {
    template<typename V> void f();
  };
};
template<typename T> // #1
template<typename U> // #2
template<typename V> // #3
void A<T>::B<U*>::f() {}

... fasse en sorte que :

L'obstacle est que la définition de template-head et de ce que ça implique est obscure et le travail démarré à ce sujet est actif depuis... dix ans. Cela dit, le texte proposé est une nette amélioration en comparaison avec l'existant, malgré ses imperfections. On envisage traite les irritants résiduels comme une Core Issue distincte. P2 pour le moment.

Core Issue 2864 Narrowing floating-point conversions

Il se trouve que :

float f = {1e100};

... est une narrowing conversion traditionnellement, mais la résolution de Core Issue 2723 l'a accidentellement rendu non-narrowing... ce qui entraîne une divergence de IEEE754. La proposition traite ce cas, en particulier dans une contexte constexpr. On discute de la représentation de l'infini ici...

On ajoute une note à l'effet qu'un narrowing conversion d'un NaN peut donner un NaN avec des bits différents. Tentatively Ready pour samedi

Core Issue 2865 Regression on result of conditional operator

On a brisé quelque chose :

#include <concepts>

template <class T> T get();
template <class T>
  using X = decltype(true ? get<T const&>() : get<T>());

struct C { };

static_assert(std::same_as<X<int>, int>);
static_assert(std::same_as<X<C>, C const>);  // #1

Auparavant, #1 compilait, mais c'est devenu ambigu car nos travaux sur les conversion sequences font qu'on peut maintenant former une séquence dans les deux sens. La proposition est de rétropédaler sur la conversion qui oublie le const.

Core Issue 2869 this in local classes

Le texte couvre mal ce cas :

struct A {
  static void f() {
    struct B {
      void *g() { return this; }
    };
  }
};

... parce qu'il utilise « appears within » ce qui pose un problème (c'est vraiment pas assez formel). On veut que ce à quoi this réfère soit clair dans le texte. Ready pour samedi

Core Issue 2870 Combining absent encoding-prefixes

C'est bête, mais on ne dit pas clairement dans le texte le fruit de la combinaison de deux littéraux sans encoding-prefix. On y reviendra.

Core Issue 2871 User-declared constructor templates inhibiting default constructors

On parle ici d'une très petite précision terminologique (manque un cas dans une énumération).

Core Issue 2872 Linkage and unclear "can be referred to"

En discutant de linkage on a une imprécision sur la nature des entités auxquelles on peut référer, et même sur ce qu'on entend par « refer to » (par nom? par adresse? autre chose?).

Le texte proposé en remplacement est plus clair, et aide à comprendre l'important c'est à dire parle-t-on de deux entités distinctes ou de la même dans chacun des cas mentionnés.

Ready pour samedi.

Core Issue 2874 Qualified declarations of partial specializations

Truc mineur : il manque un élément dans une énumération. On corrige. Ready.

Core Issue 2875 Missing support for round-tripping null pointer values through indirection/address operators

Bon, celui-ci est plus croustillant. On a une divergence entre C et C++ :

void f() {
  char *p = 0;
  char *p2 = &*p;       // OK in C, undefined behavior in C++
  char *p3 = &p[0];     // OK in C, undefined behavior in C++
  int a[5];
  int *q = &a[5];       // OK in C, undefined behavior in C++
}

Ça peut surprendre (c'était UB par omission et ce l'est explicitement depuis Core Issue 2823) alors faut au moins le documenter dans l'annexe C. Jason Merrill pense que les implémentations vont traiter le cas des tableaux de manière « évidente », mais c'est permis par les règles du comportement indéfini... sauf dans un contexte constexpr; il préfèrerait qu'on fasse une exception pour le cas &arr[N]. Hubert Tong pense que ça mérite un Core Issue tout de même car il y a de l'inconfort (c'est du code fréquemment rencontré en pratique). Plusieurs pensent qu'une proposition couvrant le cas &arr[N] arrivera rapidement.

Pause pour le dîner; je vais manquer l'après-midi pour cause de rendez-vous de routine chez le dentiste, puis une urgence qui m'a encore une fois mené à Montréal pour l'un de nos amimaux... Sur la base du Wiki, CWG a travaillé sur :

Il devait ensuite y avoir un examen de quelques Issues de niveau P1, mais il semble n'y en avoir eu qu'une seule :

P3068R2 Allowing exception throwing in constant-evaluation

Ceci semble avoir consommé pas mal de temps.

Jour 3 – 27 juin 2024

Mon plus jeune Ludo a une toux persistante et mon amoureuse Za s'est blessée au dos alors j'ai passé tout l'avant-midi à me promener entre clinique pédiatrique, centre de prélèvement et pharmacie... Je regarde donc ce qui s'est passé le matin sur la base du Wiki, espérant pouvoir participer aux travaux de l'après-midi. Ce matin donc :

P2996 Reflection for C++26

C'est un gros sujet : la salle est tellement pleine qu'on fait un tour de table!

Jens Maurer fait une introduction archi sommaire de la proposition (le passage vers et de std::meta_info).

Daveed Vandevoorde fait remarquer que la proposition permet désormais de générer des états. On réfère à l'exemple de la section 3.17 :

class TU_Ticket {
  template<int N> struct Helper;
public:
  static consteval int next() {
    int k = 0;

    // Search for the next incomplete 'Helper'.
    std::meta::info r;
    while (!is_incomplete_type(r = substitute(^Helper,
                                             { std::meta::reflect_value(k) })))
      ++k;

    // Define 'Helper<k>' and return its index.
    define_class(r, {});
    return k;
  }
};

constexpr int x = TU_Ticket::next();
static_assert(x == 0);

constexpr int y = TU_Ticket::next();
static_assert(y == 1);

constexpr int z = TU_Ticket::next();
static_assert(z == 2);

Ceci construit graduellement Helper<k> pour diverses valeurs de k. Ooookay :)

Daveed Vandevoorde rappelle qu'il est Ill-Formed d'utiliser un std::meta_info à l'exécution (même pour prendre son adresse).

On examine d'abord le nouvel opérateur unaire ^ qui pourra être appliqué à des noms de namespace (incluant ::), de classe, de template, de concept, etc. pour obtenir un std::meta_info. Un std::meta_info est ce qu'on appelle une reflection. Ça se trouve dans [expr.unary.general] pour la grammaire et ça recoupe nos réflexions (!) de la semaine sur le rôle de template-name. Ça complique un peu la discussion car c'est une cible mouvante, mais on essaie de ne pas nuire à la proposition sur cette base. Les détails de l'opérateur sont dans [expr.reflect]. Il y a possibilité d'une null reflection value.

On semble refléter des entities. Jens Maurer fait remarquer que cela signifie qu'il n'y aura pas de réflexivité sur les expressions. Ça semble intentionnel.

La grammaire proposée semble couvrir les overload sets. La mécanique est toutefois que ça ne fonctionne que s'il y a une seule fonction dedans (ou aucune, je présume).

Appliquer ^ sur une id-expression n'évalue pas cette dernière.

On ne peut pas faire de réflexivité sur un littéral, par exemple ^5, et ça semble être volontaire.

(je me suis absent. environ 25 minutes pour aller reconduire mon enfant Viktor au travail et poster un paquet; à mon retour un travaille sur les splice-expressions de la forme [:constant-expression:]; on est dans [expr.prim.splice.*])

Jens Maurer demande si on peut faire une reflection sur un bit-field. C++ est un langage divertissant...

(pause de 15 minutes; ça travaille fort)

On discute de l'interaction de [: avec le préprocesseur. On a déjà des enjeux avec les expressions λ (confusion avec la notation des tableaux.... le préprocesseur est essentiellement le même que pour le langage C après tout). Ça se passe entre autres dans [lex.phases]. Toucher à ces paragraphes est... inconfortable. En plus, il faut s'assurer de désambiguer dans le cas de digraphes...

On examine ensuite plusieurs productions grammaticales où s'ajoutent les nouvelles expressions, incluant les splice-expressions. On remarque que dans au moins un cas, il faut produire un token lookahead potentiellement infini (ça peut ralentir la compilation, disons).

Chose intéressante : il est important que les transformations réalisées par réflexivité se fassent avant la plupart des autres phases de la compilation, car les reflections permettent de raisonner sur des classes, namespaces, templates, etc. mais aussi de générer du code. Jens Maurer fait remarquer qu'on a probablement des erreurs de catégorie dans le texte en exprimant les objets de réflexivité en termes de productions grammaticales, privilégiant qu'on parle de types par exemple. J'apprends au passage que les remplacements des alias résultant de typedef et des expressions using ne se font pas au même moment dans le processus (je ne sais pas pourquoi, cela dit).

On se questionne sur la place de [: et :] partout dans la grammaire, et on se demande si lui donner une production à part entière n'allègerait pas l'entretien qui s'ensuivra.

Un autre enjeu intéressant est le choix des mots : on joue dans le même espace que la grammaire, au fond, mais on ne veut pas utiliser les mêmes verbes pour éviter de la confusion alors on travaille nos synonymes (p. ex. : denotes vs designates). Le standard existant n'est pas totalement rigoureux dans ses choix de mots ici alors ça nous nuit un peu.

Intéressant : la reflection d'un type et celle d'un de ses alias ne comparent pas égaux au sens de ==.

On a une nouvelle idée de plainly-constant-evaluated qui enrichit et englobe l'idée de constant-expression. On devient capables de définir une classe de manière programmatique dans un static_assert ou une fonction consteval par exemple.

Ces mécanismes interagissent évidemment avec les règles de l'ODR. Et avec ADL... Ouf...

On peut générer des bitfields anonymes. Il y a un (petit) enjeu terminologique dans le texte.

On a une nouvelle idée de consteval-only type. C'est quand même intéressant. Un ajout à [basic.types.general].

La prose a besoin d'amour, mais en toute honnêteté c'est franchement difficile de parler de code qui raisonne sur le code...

(il faut arrêter pour aujourd'hui)

Demain, je vais manquer le début de la journée (mon chic papa aura 80 ans la semaine prochaine et nous faisons un petit quelque chose pour lui en matinée). C'est triste parce que cette proposition est fascinante...

Jour 4 – 28 juin 2024

Comme indiqué hier, mon matin a été consacré à un déjeuner en famille avec mon chic papa Réal (80 ans le 3 juillet) et ma fille Amandine (23 ans le 1er juillet). Ce fut fort sympathique, mais j'ai manqué tout l'avant-midi à St-Louis. C'est ce genre de semaine...

Chez CWG, les travaux du matin semblent (sur la base du Wiki) avoir été :

L'objectif de l'après-midi semble être de traiter les Core Issues de niveau P1, mais il y a des trucs plus pressants.

P0963 Structured Binding declaration as a condition

Il y a une dépendance envers CWG2867 qui décrit l'ordre d'initialisation des Structured Bindings alors il faut que CWG2867 soit résolu pour que P0963 soit acceptable. On parle de permettre ceci :

if (auto [to, ec] = std::to_chars(p, last, 42)) {
   auto s = std::string(p, to);
   // ...
}

... en considérant comme condition l'objet sous-jacent au Structured Binding (on peut donc y implémenter operator bool()). On a la même mécanique pour un switch avec une conversion en un type entier. On nomme ces objet la decision variable de la condition. Faut faire attention au moment d'évaluation de la condition au cas où il y aurait un mouvement dans la mécanique synthétisant le Structured Binding.

Hubert Tong repère un risque de Vexing Parse dans la grammaire. On fouille et cela semble préexistant (ça remonte à un NB Conmment pour C++17)... On cherche une manière de limiter la localité des dégâts.

On convient collectivement qu'un Feature Test Macro ne sera pas pertinent dans ce cas.

On étudie la question de la durée de vie des temporaires matérialisées par un Structured Binding, ce qui constitue un changement au modèle des temporaires. C'est une partie de l'enjeu de CWG2867. On trouve une solution à cette dernière alors Ready. Pour les deux.

P2963 Ordering of constraints involving Fold Expressions

On se bat un peu avec la définition de valid pack expansion qui est quelque peu vaseuse.

(brève pause)

Il y a risque de code (obscur, mais valide) devenant invalide avec cette proposition, car dans un requires on exige des expressions de type bool et les conversions implicites de int à bool sont brisées. On examine ensuite des cas de subsomptions de Fold Expressions lorsque celles-ci sont utilisées à titre de contraintes pour des concepts.

Passage savoureux : on a un exemple avec une classe Thingy. Jens Maurer demande qu'on remplace Thingy par autre chose. Corentin Jabot demande « what's wrong with Thingy? ». Jens Maurer réplique « That's not a Core name ». Du bonbon!

Après près de deux heures de travail : Ready. Bravo!

P0963 Structured Binding declaration as a condition

On revient à cette proposition. Il y a eu des changements terminologiques mais ça demande un peu d'amour. On aimerait bien l'amener pour vote demain, alors on travaille fort.

(on discute au passage de la forme du rapport qui sera présenté en plénière demain). Jens Maurer mentionne qu'il y a désormais recommandation que le message d'erreur produit lors d'un crash suivant une levée d'exception non-attrapée tienne compte du texte retourné par what() ce qui soulève l'enjeu de l'encodage des chaînes de caractères.

Ready. Après beaucoup de travail.

Core Issue 2814 Alignment requirement of incomplete class type

On revient sur le problème souligné par Richard Smith. Jason Merrill remarque que si un type n'est jamais pleinement défini il ne peut probablement pas avoir de contraintes d'alignement. On vérifie et... c'est vraiment pas évident. Il n'y a probablement pas de problème a priori. On pense trancher pour NAD, mais ça se poursuit...

(c'est délicat, et je dois quitter pour des raisons familiales)

Jour 5 – 29 juin 2024

Matin de plénière et de votes. La déglégation canadienne se rencontre une trentaine de minutes avant que le tout ne démarre pour discuter de sujets contentieux pour le pays, mais rien ne me frappe de ce dont j'ai eu connaissance cette semaine. J'ai appris des trucs intéressants mais confidentiels; pour les votes de ce matin, ma lecture ressemble à celle de mes illustres collègues.

Lors de la plénière, on a de chouettes progrès chez SG1 et SG6 (SIMD semble proche, peut-être pour C++26, et il en va de même pour concurrent_queue). Pour SG7 on parle de six propositions sur sept relayées à EWG ou LEWG. SG9 a eu une rencontre conjointe avec SG1 pour discuter d'algorithmes parallèles. SG15 poursuit ses travaux sur l'écosystème et sur les stratégies d'implémentation pour les contrats. EWGI a eu une semaine relativement productive (incluant « The Oxford Variadic Comma », un nom anusant). LEWGI a tenu deux rencontres. SG19 a tenu une rencontre sur ses sujets habituels (leur gros dossier est std::graph et les statistiques). SG21 a eu une grosse semaine, manifestement, avec deux journées pleines à la suite d'une grosse rencontre de EWG sur les contrats; en particulier, les contrats sur les fonctions virtuelles ont passé à la fois SG21 et EWG. Un effort pour unifier l'introduction du nom de la valeur de retour sur une postcondition et dans le pattern matching est en cours. SG22 ne s'est pas rencontré mais progresse en asynchrone. SG23 a eu une pleine journée de rencontre avec P3274 sur les profils (la notation par annotations semble préférée à celle par mots clés), le erroneous behavior s'en va à EWG, et il y a eu la présentation de Sean Baxter sur le Borrow Checker qui a reçu la faveur du groupe.

EWG a eu une grosse semaine avec les contrats et des propositions de fond, incluant Reflection qui a été relayée à CWG.

LEWG a progressé sur plusieurs fronts, mais avec des votes en personne seulement (l'objectif est de ne pas tenir de votes électroniques lors de rencontres in vivo). Les dossiers d'ordre politique avancent bien (on a une marche à suivre pour [[nodiscard]] désormais, de même que pour les constructeurs explicit). Pour P2626 on demande l'aide de CWG : le problème est réel, mais LEWG n'a pas les clés pour faire progresser ce dossier. On parle aussi du Beman Project (excellente idée!). Herb Sutter rappelle que LWG est saturé et risque de ne pas pouvoir livrer tout ce qui est sur sa table pour C++26; Inbal Levi dit que LEWG va les prioriser.

CWG Polls

On présente ce que CWG a fait cette semaine, expliquant le processus au passage. On porte une attention particulière à certains aspects :

Les propositions retenues suivent. Ayant participé à l'essentiel des travaux, je suis en faveur de celles-ci. On passe au vote

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

Unanime

2. Apply the proposed resolution of issues 2819, 2858, and 2876 in P3345R0 (Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper.

Unanime

3. Apply the changes in P2747R2 (constexpr placement new) to the C++ Working Paper.

Unanime

4. Apply the changes in P1061R9 (Structured Bindings can introduce a Pack) to the C++ Working Paper.

Il y a opposition car on note que plusieurs exemples dans la proposition ne compilent pas sur l'implémentation de référence. Ça ne semble pas avoir été discuté chez EWG, car il s'agit d'enjeux d'implémentation.

On vote. Pas de consensus. Ça retournera à EWG.

5. Apply the changes in P3144R2 (Deleting a Pointer to an Incomplete Type Should be Ill-formed) to the C++ Working Paper.

Unanime

6. Apply the changes in P2963R3 (Ordering of constraints involving fold expressions) to the C++ Working Paper.

Unanime

7. Apply the changes in P0963R3 (Structured binding declaration as a condition) to the C++ Working Paper.

Opposition. On vote. Consensus, mais avec beaucoup d'abstentions.¸C'est pas un enjeu (ça peut vouloir dire que les votant(e)s ne sont pas au fait du dossier). Pas d'opposition de NB.

LWG Polls

On présente le travail colossal fait cette semaine, surtout sur P2033 std::execution. SIMD est fait à approximativement 60%, et plusieurs propositions plus petites ont été traitées et sont soumises au vote aujourd'hui.

J'ai fait le tour des propositions et à mes yeux, les deux qui peuvent « brasser » un peu sont P3168 (ce n'est pas tout le monde qui pense que c'est une bonne idée ou que ça passe le bon message, mais je suis plutôt « pour » personnellement), P0843 (parce qu'il y a un enjeu quant au support ou pas d'allocateurs – ils sont absents de la proposition, mais peuvent jouer un rôle dans un contexte PMR) et P2300 (parce que c'est gigantesque).

1. Apply the changes for all Ready and Tentatively Ready issues in P3341R0 (C++ Standard Library Ready Issues to be moved in St. Louis, Jun. 2024) to the C++ working paper.

Unanime

2. Apply the changes in P2997R1 (Removing the common reference requirement from the indirectly invocable concepts) to the C++ working paper.

Unanime

3. Apply the changes in P2389R2 (dextents Index Type Parameter) to the C++ working paper.

Unanime

4. Apply the changes in P3168R2 (Give std::optional Range Support) to the C++ working paper.

Opposition. On vote. Consensus

5. Apply the changes in P3217R0 (Adjoints to "Enabling list-initialization for algorithms": find_last) to the C++ working paper.

Unanime

6. Apply the changes in P2985R0 (A type trait for detecting virtual base classes) to the C++ working paper.

Unanime

7. Apply the changes in P0843R14 (inplace_vector) to the C++ working paper.

On note que ceci avait été retiré du vote à Tokyo et que les travaux à faire furent faits. Il y a opposition. On vote. Consensus

8. Accept as a Defect Report and apply the changes in P3235R3 (std::print more types faster with less memory) to the C++ working paper.

Unanime

9. Apply the changes in P2968R2 (Make std::ignore a first-class object) to the C++ working paper.

Opposition. On vote. Consensus

10. Apply the changes in P2075R6 (Philox as an extension of the C++ RNG engines) to the C++ working paper.

Unanime

11. Apply the changes in P2422R1 (Remove nodiscard annotations from the standard library specification) to the C++ working paper.

Unanime

12. Apply the changes in P2300R10 (std::execution) to the C++ working paper.

On a une demande de NB qui souhaiterait que le vote soit remis à Wroclaw (Pologne) en novembre dans le but d'accroître le consensus. On mentionne des enjeux quant à la complexité de l'API et la capacité de l'enseigner. La discussion s'ensuit pour mettre en relief la complexité de cette API dans son état actuel. Ça joue dur...

Il y a manifestement opposition. On vote. C'est sur la frontière du consensus. On demande les positions des NB. On a des peut-être, pas des « non » fermes. On déclare le consensus, sur la base du fait qu'on travaille là-dessus depuis 2016, mais on rappelle que si on constate que les problèmes soulevés ne sont pas résolus il y a toujours la possibilité de retirer ceci du Working Draft.

(je dois quitter après les votes dû à une urgence familiale)


Valid XHTML 1.0 Transitional

CSS Valide !