À propos de WG21, Hagenberg 2025 (février)

Je participe à cette rencontre à distance. La rencontre de cette semaine se tenant à Hagenberg (Autriche), le décalage horaire sera rude, et j'ai des dossiers à défendre alors ce sera une semaine quelque peu... physique. Je ne serai que partiellement présente à cette rencontre alors soyez tolérantes et tolérants envers moi s.v.p.

Les principaux thèmes de la rencontre sont la progression des travaux pour C++ 26, en particulier la réflexivité statique et – surtout – les contrats. Je devrais passer ma semaine chez CWG comme à mon habitude, mais j'ai [[invalidate_dereferencing]] à défendre alors je vais investir du temps dans SG23.

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 – 10 février 2025

Je suis arrivé (virtuellement) à la rencontre vers 8 h 45 heure de Hagenberg (2 h 45 heure locale). J'avais programmé la cafétière avant de me coucher, mais j'avais oublié d'appuyer sur « démarrer » alors ce fut un démarrage « physique » ce matin, mais heureusement le café était prêt à temps 🙂

John Spicer fait l'accueil comme il se doit, puis Peter Bindels (notre hôte) se présente et offre quelques mots. Notre système de Wiki s'est fortement raffiné depuis la rencontre de Wrocław en 2024. Les règles de fonctionnement nous sont rappelées, incluant celles en lien avec le code de conduite (comme il se doit). Depuis que notre secrétaire Nina Ranns a pris ce dossier en mains, elle lui a donné beaucoup de coffre (bravo Nina!).

Les règles associées au processus de vote sont rappelées, les principaux officiers du comité sont présentés, et on laisse la place aux nouvelles participantes et aux nouveaux participants pour que ces chics individus se présentent et expliquent la raison de leur participation. On a quelques membres de la communauté Rust avec nous cette fois, surtout en lien avec l'interopérabilité entre les deux langages, et on a des contributeurs du monde de l'infonuagique intéressés par la sécurité (entre autres).Certains participants sont des gens qui contribuent informellement depuis longtemps et sont avec nous pour une première fois (c'est ce qui se passe dans bien des cas quand nous tenons nos rencontres dans des endroits que nous n'avions pas visités).

On nous rappelle que le principal sujet pour la semaine est la complétion de la liste de mécanismes qui feront partie de C++ 26. Jens Maurer explique les règles de logistique (répartition des groupes d'étude et des groupes de travail par salle, selon les jours; accès aux sources de courant électrique; accès à la nourriture; etc.).

Il y a un photographe sur place qui prend une photo de groupe (je n'y serai pas, étant à distance).


Comme c'est mon habitude, je passerai le plus clair de ma semaine avec mes ami(e)s de CWG, mais je ferai une excursion chez SG23 mardi après-midi (heure de Hagenberg) pour présenter la R1 de P3442 – [[invalidate_dereferencing]]. On rode un peu la logistique puis on procède (nous avons quelques étudiantes et quelques étudiants de l'université qui nous sert d'hôtesse avec nous ce matin).

D2996R10 - Reflection for C++26

On commence fort! On vit un problème technique : il y a tellement de clics concurrents sur certaines pages que l'université provoque ce que le Wiki pense être un DDoS 🙂

On bascule vers une autre proposition le temps que le problème se règle

D3289R2 - consteval blocks

Barry Revzin explique la raison d'être de ce type de bloc, qui sera particulièrement utile avec l'avènement de la réflexivité statique : ce qui se place dans un consteval { /*...*/ } sera évalué durant la production de l'unité de traduction. En gros, ceci :

consteval {
   stmt;
}

... sera équivalent à cela :

consteval {
   []() -> void consteval {
      stmt;
   }(), true
}

Ça introduit de nouvelles productions grammaticales comme vacant-declaration. Walter Brown recommande de remplacer vacant par vacuous qui est un terme plus usité; Barry Revzin procède.

On se questionne sur le moment de l'évaluation de cette hypothétique lambda. Pour ce faire, on revient à D2996...

D2996R10 - Reflection for C++26

L'enjeu du point d'évaluation de cette hypothétique lambda est qu'on utilise ces blocs pour du code génératif, alors clarifier ceci permet parfois de savoir si un type est complet ou incomplet au moment de la génération. On a un enjeu conceptuel à savoir si les évaluation se font « à l'exécution » mais de manière transparente et non-observable ou « à la compilation » qui est ce que semble suggérer la proposition (on y étend l'idée de « compile-time side-effects »!)

Un autre enjeu est la portée d'une injection de code. Par exemple :

consteval void complete_type(std::meta::info r) {
  std::meta::define_aggregate(r, {});
}

struct S1;
consteval { complete_type(^^S1); }  // OK

template <std::meta::info R> consteval void tfn1() {
  complete_type(R);
}

struct S2;
consteval { tfn1<^^S2>(); }
  // OK, tfn1<^^S2>() and S2 are enclosed by the same scope

template <std::meta::info R> consteval void tfn2() {
  consteval { complete_type(R); }
  return b;
}

struct S3;
consteval { tfn2<^^S3>(); }
  // error: complete_type(^^S3) is enclosed tfn2<^^S3>, but S3 is not

template <typename> struct TCls {
  struct S4;
  static void sfn() requires ([] {
    consteval { complete_type(^^S4); }
    return true;
  }) { }
};

consteval { TCls<void>::sfn(); }
  // error: TCls<void>::S4 is not enclosed by requires-clause lambda

struct S5;
struct Cls {
  consteval { complete_type(^^S5); }
    // error: S5 is not enclosed by class Cls
};

struct S6;
consteval { // #1
  struct S7;
  consteval { // #2
    define_aggregate(^^S6, {});
      // error: consteval block #1 encloses consteval block #2 but not S6
    define_aggregate(^^S7, {});  // OK, consteval block #1 encloses both #2 and S7
  }
}

Faudra s'habituer à la syntaxe, évidemment, et faudra s'habituer au niveau (quelque peu stratosphérique) d'abstraction. Brian Bi questionne la possibilité de générer des templates dans un tel contexte (on fait remarquer qu'il y a des restrictions sur la présence de classes génériques dans une fonction). Le cas S4 semble être la clé pour ce qui doit être exprimé ici.

Vlad Sebrennikov suggère qu'on porte une attention particulière aux membres des lambdas à travers std::meta::members_of(). On fait au passage remarquer que certains passages écrits par LWG seront aussi révisés par CWG car plusieurs aspects de la réflexivité exposent des Compiler Internals et qu'il faut s'assurer que le tout satisfasse l'ensemble des auteurs de compilateurs dans la salle. Dans le cas des lambdas, un vendeur peut offrir des opérateurs de conversion pour diverses conventions d'appel, ce qui modifie l'ensemble de ce qui sera exposé d'un compilateur à l'autre; conséquemment, on se questionne à savoir si les conversions exposées devraient se limiter à celles spécifiées par le standard... mais même circonscrire ceci semble être un défi! On va consulter EWG à ce sujet.

Les lieux où du code est généré sont des Synthesized Points. On examine ce qui, dans un programme, est influencé par un Synthesized Point, puis on examine la question associée du Module Reachability pour voir ce qui, dans du code généré, est exposée aux autres modules.

(pause pour dîner vers midi heure de Hagenberg, 6 h à Montréal)

J'ai manqué les vingt premières minutes de l'après-midi car j'ai appris... que je suis devenu grand-papa au cours de la nuit! Ma fille Calypso a donné naissance à Blanche, sa première (un bébé très prématuré, mais qui semble Ok dans sont incubateur, et la maman semble Ok elle aussi... Ouf!)

D2900R14 - Contracts for C++

J'ai quelques minutes à peine pour voir ce qui se passe car je dois aller donner une prestation de cours (à distance, dans les circonstances). C'est un sujet important, j'irai lire les minutes plus tard aujourd'hui.

Jour 1 – 11 février 2025

Je ne sais pas comment ça s'est produit (j'avais mis un tas d'alarmes en place, et du café!) mais j'ai trop dormi (!) et je me suis levé à 4 h du matin, manquant le premier bloc de travail du matin (je me suis joint à CWG juste après la première pause). On travaillait alors sur D2841

D2841 – Concept and variable-template template-parameters

C'est un effort important. En gros, l'idée est de permettre :

template<
  template <typename T> concept C,
  template <typename T> auto V
>
struct S{};
template <typename T>
   concept Concept = true;
template <typename T>
   constexpr auto Var = 42;
S<Concept, Var> s;

Je suis arrivé alors que CWG étudiait la terminologie en détail. On discute entre autres de l'importance d'interdire :

template <
  template <typename> concept C,
  template <C> class TT // error: C forms a concept-dependent constraint
>
struct A {}

... parce que c'est juste pas vérifiable.

C'est un sujet très abstrait, et les termes le sont aussi. On a quelques cas où on hésite entre « same kind » et « same form » par exemple, et on cherche l'abstraction qui mérite le plus d'être définie. On a aussi un enjeu de terminologie, car les concepts sont à un niveau d'abstraction plus haut que celui des autres templates : si on a template<int> class C; alors C<3> n'est pas un template, c'est une classe, mais si on a template <class> concept C; alors C<string>... n'est pas un concept. Qu'est-ce, sur le plan de la nomenclature? Il nous faut trouver les mots pour nommer ces choses.

La généralisation des concepts dans les paramètres de templates accroîtra (quand ce sera fignolé) fortement l'expressivité du langage. Dans une de mes propres conférences l'an passé, j'ai soulevé le problème de ne pas pouvoir exprimer un concept à partir de contraintes exprimées par un concept (il y a des voies de contournement, heureusement!). Cette proposition me semble régler cet irritant.

L'essentiel du travail ce matin est l'examen d'exemples très intéressants mais très abstraits de substitutions et de subsomptions de concepts. Une partie importante de cet effort est de s'assurer que les exemples portent le message approprié, et dans le Core Language c'est une aventure pour programmeuses averties et pour programmeurs avertis!

Brève pause-dîner, puis je vais à SG23 où je devrai porter ma présentation sur P3442, [[invalidate_dereferencing]].

P3356 – non_invalidating_vector

Jarrad Waterloo présente son idée qui est d'offrir une vue sur un std::vector<T> qui ne permettrait pas d'opérations invalidantes (une interface limitée aux membres const). Il pense que son idée pourrait s'appliquer à std::string aussi, mais se concentre sur std::vector<T> en ce moment.

Une des approches auxquelles il réfléchit est d'ajouter une classe parent à std::vector<T> de manière à ce que le parent soit plus restrictif que l'enfant (personnellement, ça me semble être un bris d'ABI). L'autre (un non_invalidating_vector_ref<T> qui servirait de « wrapper ») semble plus féconde et pourrait s'appliquer à std::inplace_vector<T> par exemple.

Patrice Roy demande en quoi cette classe, dans sa version non-owning, diffère de std::span<const T>. Jarrad Waterloo n'est pas certain; faudra explorer.

P3402 – A Safety Profile Verifying Class Initialization

Marc-André Laverdière présente. Sa perspective est celle d'un artisan de l'analyseurs statique Coverity. Le profil proposé vise l'initialisation de manière générale. Ils proposent entre autres un std::verified_cast. L'idée est de définir des objets vérifiés et des opérations vérifiées, et de ne pas permettre (avec ce profil) d'utiliser des objets et des opérations qui ne sont pas vérifiés.

À l'oeil, verified_cast() ressemble à std::launder() (j'ai demandé, Marc-André Laverdière ne semblait pas connaître std::launder() alors c'est peut-être un problème pré-résolu). On peut utiliser [[indeterminate]] pour exempter un objet des vérifications faites par le profil. J'ai aussi demandé si on devait initialiser explicitement les instances de classes vides; Marc-André Laverdière va vérifier, ne s'étant pas posé la question au préalable. Une des règles proposées vise à empêcher l'affectation dans un constructeur (imposer l'initialisation à la construction); ça me semble raisonnable d'un point de vue d'efficacité, mais sur le plan du Safety je reste perplexe. Marc-André Laverdière m'explique que c'était une demande de SG23 qui fut intégrée au profil pour accroître le consensus.

Il y a des recoupements avec le Erroneous Behavior, mais Marc-André Laverdière signale que leur profil est purement statique et s'applique à du code source pré-C++23.

P3442 – [[invalidate_dereferencing]]

Je vous passe les détails, mais ça s'est bien passé et j'ai un vote unanime pour porter cette proposition à l'attention de EWG.

P3541 – Violation handlers vs noexcept

Andrzej Krzemieński présente sa perspective quant aux «handlers » qui réagissent à un bris de contrat. Il donne deux cas pertinents pour lever une exception dans un tel handler : faire un test pour voir si le code réagit bien, et récupérer d'un véritable bogue dans un contexte ou planter n'est pas une option. Il fait remarquer que les « profiles » risquent de lever une exception dans certaines circonstances hors du contrôle du code source. Il mentionne noexcept(p->clear()) qui serait true car clear() est noexcept, mais avec certains profils on aura une exception si p==nullptr, ou encore lever une exception implicitement à travers un « profile » en débordant d'un tableau dans un destructeur.

C'est un vrai problème. Si on n'est pas prudents, l'ajout des « profiles » va imposer l'injection de code de Stack Unwinding partout de manière préventive, ce qui fera grossir les binaires. On se retrouvera avec le même genre d'ennui que quand on avait les spécifications throw(X,Y,Z) sur les fonctions. Augh!

Andrzej Krzemieński ne demande pas de vote, voulant surtout nous informer de la situation. On examine des avenues pour informer les autres groupes. Andrzej Krzemieński parle d'une alternative un peu exotique, mais qui n'est pas testée et ne règlerait pas le problème. On tient tout de même un vote pour demander à EWG de tenir compte de l'information dans cette proposition dans le contexte des « profiles ».

(un des présentateurs prévus ne s'est pas présenté, justement, alors on a ensuite des discussions plus informelles sur la proposition de « Safe C++ » par Sean Baxter, qui n'est pas ici cette semaine, pour voir si c'est encore possible de l'intégrer à la direction que prend C++)

J'ai ensuite fait un peu de trucs procéduraux (je n'avais pas mis la bonne version de P3442 dans le système de suivi des propositions, et je ne savais pas comment corriger mon erreur, mais ça s'est bien passé) puis je suis allé faire dodo...

Jour 2 – 12 février 2025

Lever du corps difficile, mais à 9 h du matin (3 h à Montréal) je suis au poste avec mes amis de CWG qui oeuvrent depuis 8 h 30.

D2900R14 – Contracts for C++

On parle ici d'une proposition de 119 pages. À mon arrivée, on discute du type (const ou pas) des copies des paramètres utilisés dans une précondition ou dans une postcondition, en particulier pour les coroutines. Il semble que decltype() pourrait ne pas toujours donner le type souhaité pour ce contexte, alors qu'une partie du texte exprime le type sur la base de cet opérateur alors on examine des alternatives. C'est important parce que les contrats font ce qu'on nomme une « constification » des paramètres et c'est un phénomène qu'on vise à décrire correctement.

Par exemple :

int n = 0;
struct X { bool m(); };
struct Y {
  int z = 0;
  void f(int i, int* p, int& r, X x, X* px)
    pre (++n) // error: attempting to modify const lvalue
    pre (++i) // error: attempting to modify const lvalue
    pre (++(*p)) // OK
    pre (++r) // error: attempting to modify const lvalue
    pre (x.m()) // error: calling non−const member function
    pre (px->m()) // OK
    pre ([=,&i,*this] mutable {
    ++n; // error: attempting to modify const lvalue
    ++i; // error: attempting to modify const lvalue
    ++p; // OK, refers to member of closure type
    ++r; // OK, refers to non−reference member of closure type
    ++this->z; // OK, captured *this
    ++z; // OK, captured *this
    int j = 17;
    [&]{
       int k = 34;
       ++i; // error: attempting to modify const lvalue
       ++j; // OK
       ++k; // OK
    }();
    return true;
}());
template <int N, int& R, int* P>
  void g()
    pre(++N) // error: attempting to modify prvalue
    pre(++R) // error: attempting to modify const lvalue
    pre(++(*P)); // OK
  int h()
    post(r : ++r) // error: attempting to modify const lvalue
    post(r: [=] mutable {
      ++r; // OK, refers to member of closure type
      return true;
    }());
  int& k()
    post(r : ++r); // error: attempting to modify const lvalue
};

Pour les préconditions et les postconditions de lambdas, on ne permet pas de capturer implicitement (avec [=]) des copies de variables locales, car il peut y avoir un coût à la destruction de ces objets, mais on peut les capturer explicitement (par exemple, [i]) ce qui constitue un geste volontaire. Le texte qui explique ceci est un peu lourd, on travaille dessus pour mieux (et plus simplement) porter l'intention. C'est parfois subtil, comme dans les cass f4 et f5 ci-dessous :

static int i = 0;
void test() {
  auto f1 = [=] pre(i > 0) { // OK, no local entities are captured.
};
int i = 1;
auto f2 = [=] pre(i > 0) { // error: cannot implicitly capture i here
};
auto f3 = [i] pre(i > 0) { // OK, i is captured explicitly.
};
auto f4 = [=] {
  contract_assert(i > 0); // error: cannot implicitly capture i here
};
auto f5 = [=] {
  contract_assert(i > 0); // OK, i is referenced elsewhere.
  (void)i;
};
auto f6 = [=] pre([]{
  bool x = true;
  return [=]{ return x; }(); // OK, x is captured implicitly.
}()) {};
bool y = true;
auto f7 = [=] pre([=]{ return y; }()); // error: outer capture of y is invalid.
}

Le texte proposé dans le commentaire pour f6 n'est pas suffisamment clair, alors on retravaille cette partie de l'exemple (ce qui doit ressortir est que l'enjeu est que la précondition est sur la lambda externe, par sur la lambda interne). On retravaille l'exemple, le commentaire, mais aussi la disposition pour que ce soit plus limpide. Idem pour f7.

(brève pause vers 4 h 15 du matin heure de Montréal, puis on reprend)

Une partie des efforts va sur le séquencement des opérations. La mécanique des contrats introduit des moments (hypothétiques ou réels, selon les modes de compilation choisis) où des opérations sont injectées, des créations (donc des destructions) de temporaires, etc. Inévitablement, quand on discute de temporalité, ça devient compliqué.

Les interactions avec le code exprimé à la compilation sont parfois subtiles, influençant le moment de l'évaluation (s'il y en a une; ça dépend du mode de compilation) et l'avènement (ou pas) de comportement indéfini :

constexpr int l(int c) pre(c >= 2) {
  return (c % 2 == 0) ? c / 0 : c;
}
const int i0 = l(0); // dynamic initialization causes a contract violation or is undefined behavior
const int i1 = l(1); // static initialization to 1 or contract violation at compile time
const int i2 = l(2); // dynamic initialization has undefined behavior
const int i3 = l(3); // static initialization to 3

Les postconditions ont cettre particularité qu'elles introduisent un nom au choix du code client pour nommer ce qui sera, éventuellement, la valeur de retour, ce qui est novateur sur le plan grammatical et pose des défis (par exemple, si on veut savoir que r ci-dessous est int, alors il faut consommer le texte de la fonction entière d'abord) :

auto f()
  post(r : r == 7) // OK
  {
    return 7;
  }

En examinant la grammaire, on penser trouver un bogue important quant à la position grammaticale des spécifications (optionnelles) de contrats, ce qui amène des débats « affirmés ». Le ton monte un peu, mais on convient de faire un changement.

L'équivalence de fonctions en présence de spécification de contrats implique des enjeux d'ODR. Par exemple :

bool b1, b2;
void f() pre (b1) pre ([]{ return b2; }());
void f(); // OK, function−contract−specifiers omitted
void f() pre (b1) pre ([]{ return b2; }()); // error: closures have different types
void f() pre (b1); // error: function−contract−specifiers only partially repeated
int g() post(r : b1);
int g() post(b1); // error: mismatched result−name−introducer presence
namespace N {
  void h() pre (b1);
  bool b1;
  void h() pre (b1); // error: not same by odr
}

On fait une pause pour dîner. Il est 6 h à Montréal. Le plan est de poursuivre avec les contrats cet après-midi (il semble possible de mener à terme le traitement de cette proposition cette semaine, et d'intégrer – si tout va bien – les contrats à C++26 cette semaine!)

On poursuit l'analyse détaillée de D2900R14. On retravaille le texte qui exprime l'idée que les contrats ne participent pas au processus de Overload Resolution (le texte proposé était un peu mêlant). On examine ensuite l'interaction entre l'introduction des alias pour la valeur de retour et l'exécution du programme. Par exemple :

int f()
  post(r : (const_cast<int&>(r) = 1))
  post(r : r == 1) // The postcondition checks succeed if
{ // both predicates are evaluated.
   return 0;
}
void g()
{
  int i = f();
  contract_assert( i == 1 ); // succeeds if first postcondition evaluated
}

Vous conviendrez que celui-ci est pervers. Ou encore celui-ci, qui met RVO en valeur et montre que l'introduction d'une temporaire peut impacter le sens d'un programme :

struct A {};
struct B {
  B() {}
  B(const B&) {}
};
template <class T>
  T f(T* const ptr)
  post(r: &r == ptr)
  {
    return {};
  }
int main() {
  A a = f(&a); // The postcondition check can fail if the implementation introduces
  // a temporary for the return value ( [class.temporary]).
  B b = f(&b); // The postcondition check succeeds.
}

Truc que je ne suspectais pas : les contrats impactent la signature des fonctions, et pour cette raison il faut examiner les fonctions « remplaçables » de la bibliothèque standard (p. ex. : operator new()) et s'assurer que le texte décrivant les règles d'un remplacement soit conséquent.

On exige d'ailleurs une équivalence jeton-pour-jeton ici, alors dans l'exemple suivant les A::x sont requis même dans le contexte de A :

class A {
  typedef int I; // private member
  I f() pre(A::x > 0);
  friend I g(I) post(A::x <= 0);
  static I x;
  template<int> struct Q;
  template<int> friend struct R;
protected:
  struct B { };
};
A::I A::f() pre(A::x > 0) { return 0; }
A::I g(A::I p = A::x) post(A::x <= 0);
A::I g(A::I p) { return 0; }
A::I A::x = 0;
template<A::I> struct A::Q { };
template<A::I> struct R { };
struct D: A::B, A { };

Il y a beaucoup de travail accompli sur la clarté du texte. Chez CWG, les espaces et les virgules sont extrêmement importants.

(brève pause à 9 h 15 heure de Montréal; j'en profite pour démarrer un peu de lessive)

On examine les préconditions et les postconditions des constructeurs et des destructeurs, pour faire remarquer qu'accéder implicitement à un membre d'instance dans les préconditions d'un constructeur ou dans les postconditions d'un destructeur est malformé. On permet de passer par this explicitement (si les gens y tiennent...)

Sans surprises, les spécialisations d'un template ne sont pas assujetties au contrat (s'il y en an un) du cas général.

Les exceptions introduisent un cas subtil : quand la fonction est un bloc try, alors une exception levée par une précondition ou une postcondition n'est pas techniquement dans le corps de la fonction et ne sera pas attrapée, ce qui peut mener à un appel à std::terminate().

On fait remarquer que suite aux travaux d'EWG hier, les contrats sur les fonctions membres virtuelles ne seront pas permises en C++26. On verra pour le futur.

Ouf! Si LWG est d'accord, on amènera cet énorme document de 119 pages pour vote samedi! Il est 17 h à Hagenberg quand on termine ceci...

P2786R12 – Trivial Relocatability for C++26

Pablo Halpern rappelle que l'intention est de permettre de faire en sorte qu'un objet qui peut être déplacé par une simple copie de bits le soit. On a de nouveaux mots clés contextuels, choisis par EWG (trivially_relocatable_if_eligible, replaceable_if_eligible). La proposition s'applique entre autres à std::shared_ptr, std::unique_ptr, std:vector, std::optional, la plupart des implémentations de std::string (sont exclues celles qui font le choix de garder à l'interne un pointeur sur elles-mêmes), etc.

Puisqu'on n'a qu'une trentaine de minutes pour ce dossier aujourd'hui, Pablo Halpern nous présente une explication détaillée du design et des cas d'utilisation. On commence ensuite un examen de la terninologie proposée, mais on n'a qu'une dizaine de minutes alors on utilise ce temps principalement pour soulever des questions. Entre autres, Hubert Tong remarque un bris de code existant où avec les changements proposés, une phrase qui était autrefois un champ de bit devient une déclaration de classe (syntaxiquement valide, sémantiquement malformée)... Ouf!

Assez pour aujourd'hui. On reprend les travaux la nuit prochaine...

Jour 3 – 13 février 2025

J'ai encore une fois eu de la difficulté à me lever, alors je me suis joint à mes collègues de CWG à 4 h 30 heure de Montréal (pendant la pause du matin). C'est une semaine très... physique pour moi. Le document sur lequel le groupe a travaillé en mon absence est D2841R7 – Concept and variable-template template-parameters.

Après la pause, on aborde d'autres dossiers. Jens Maurer fait remarquer qu'un bogue a été trouvé dans un des documents approuvés cette semaine (Trivial Unions, sur lequel je n'ai pas travaillé personnellement) alors on le retire de ceux soumis au vote samedi, du moins pour le moment.

D2287 – Designater Initializers for Base Classes

L'idée est que, étsant donné les agrégats suivants :

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

... il devienne possible de faire :

B{{1}, 2}         // already valid in C++17
B{1, 2}           // already valid in C++17

B{.a=1, .b=2}     // proposed
B{{.a=1}, .b=2}   // proposed
B{.a{1}, .b{2}}   // proposed
B{.b=2, .a=1}     // still ill-formed

Ça semble raisonnable, en toute honnêteté. On examine les changements grammaticaux que cela implique. On remarque un problème dans le contexte d'une classe avec plusieurs parents (la production grammaticale proposée ne couvre pas correctement ce cas) et une possible ambiguïté dans le nommage d'un parent. On discute avec Barry Revzin de ses intentions étant donné que la proposition ne couvre pas vraiment les cas qu'elle dit couvrir. On discute de l'intérêt de retourner cette proposition devant EWG pour valider que l'intention est bien comprise de toutes et tous.

Le fait que le nommage soit récursif ici rend la définition des clauses grammaticales plutôt subtiles. Un exemple décrivant l'intention est :

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};

struct A2 : A { int a; };

// the A element is not explicitly initialized
A2 z = {.a=1};

L'intention semble aussi de pouvoir intégrer des union anonymes dans ces hiérarchies d'agrégats, mais on découvre que la terminologie, dans ses choix de mots, ne le permet pas.

Dans l'exemple suivant :

struct base1 { int b1, b2 = 42; };
struct base2 {
  base2() {
    b3 = 42;
  }
  int b3;
};
struct derived : base1, base2 {
  int d;
};

derived d1{{1, 2}, {}, 4};
derived d2{{}, {}, 4};
derived d3{{1, 2}, {}, .d=4};

... on a :

On le reverra quand la proposition aura été retravaillée, et peut-être revue par EWG. Sans doute lors d'une rencontre future (cette semaine, l'horaire est trop chargé).

P2719 – Type-aware allocation and deallocation functions

C'est un sujet dont je traite dans mon livre sur la gestion de la mémoire, livre qui sera disponible sous peu (yay!). L'idée est bonne, mais le texte a besoin d'un peu d'amour. On finit l'avant-midi en essayant de trouver les bons mots pour les idées quis sous-tendent ce que cette proposition essaie d'apporter.

(brève pause pour dîner; il est 6 h à Montréal)

P2758R5 – Emitting messages at compile-time

Jason Merrill se porte volontaire pour examiner la terminologie

P2014R2 – Proposed resolution for US061+US063 - aligned allocation of coroutine frames

On cherche des volontaires pour celle-là, elle est plus croustillante.

P2786R13 – Trivial Relocatability for C++26

On examine les changements apportés depuis hier. Jens Maurer explique qu'il a épluché ce document avec les auteurs hier soir, ce qui explique qu'il ait beaucoup moins de commentaires à formuler maintenant qu'à son habitude.

Des critiques sont formulées à propos des suffixes _if_eligible des nouveaux mots clés. C'est verbeux; on signale ce fait à EWG.

Arthur O'Dwyer fait remarquer que les règles décrivant la capacité implicite de relocalisabilité triviale traitent de manière légèrement incorrecte l'affectation dans le cas où cet opérateur est hérité. Il propose cet exemple :

struct Cat {};
struct Leopard : Cat {
    int spots_;
    Leopard& operator=(Leopard&) = delete;
    using Cat::operator=;
};
static_assert(is_trivially_copyable_v<Leopard>);
static_assert(is_trivially_assignable_v<Leopard &, const Leopard&>);

void test(Leopard &a, const Leopard &b) {
  a = b; // absolutely no data is copied
}

On examine en détail les règles qui font qu'un type est trivialement relocalisable, et celles qui font qu'un type est remplaçable. On utilise la forme unless ce qui permet de dire que les types le sont par défaut, sauf si certaines particularités sont relevées.

On signale que les union ont un traitement un peu différent; les raisons semblent être la possibilité des union anonymes (on mentionne aussi qu'une proposition sur les union triviaux est en vol en ce moment, et que cela rend les union plus... intéressants).

On doit examiner un peu le Library Wording (ce qu'on ne fait pas habituellement) car il y a des recoupements avec le Core Wording. Les fonctions qui nous touchent sont std::relocate() et std::trivially_relocate(). C'est difficile de bien définir les intervalles source et destination, avec des termes comme potentially overlapping subobjects. L'enjeu est les trucs comme [[no_unique_address]]... Il semble nous manquer un terme pour bien circonscrire ces cas subtils.

Parler des objets post-relocalisation est aussi subtil : on essaie « ...whose object representations are the original object representations of the corresponding objects in the source range » ce qui signifie que les bit patterns avant et après doivent être identiques, ce qui peut être un enjeu avec les pointeurs (les pointeurs sont plus que de simples adresses, surtout sur des machines contemporaines qui tracent leur provenance, et surtout si on tient compte des pointeurs de fonctions). Si on n'est pas prudents, il faudra faire de la magie noire pour que ça fonctionne. C'est un enjeu parce que l'intention derrière le design est de permettre des types polymorphiques qui soient trivialement relocalisables, mais la vtbl devient un obstacle... Va falloir ajuster le texte ou changer le design (on a des alternatives, mais on se ramasse avec des enjeux quant aux bits de padding et c'est pas plus simple)

(la salle s'échauffe un peu... brève pause vers 9 h 15 heure de Montréal)

On reviendra à la relocalisation plus tard

P1967R13 – #embed - a scannable, tooling-friendly binary resource inclusion mechanism

C'est une proposition qui a été vue par le passé, la dernière fois il y a un an environ. On refait le tour de la grammaire. C'est du texte inspiré de celui pour #include qui est plutôt vieux et montre son âge...

Le texte généré par un #embed devait être une séquence de unsigned char. C'est un peu déplaisant pour les implémenteurs de générer des casts pour chaque symbole (on n'a pas de littéral standard de ce type). On va y aller avec une séquence de littéraux entiers.

(ne vous trompez pas s'il n'y a pas beaucoup de texte ici; on a passé deux heures sur cette proposition, mais c'est un peu technique : il y a des liens entre l'encodage du fichier source et l'encodage de l'environnement d'exécution; on essaie de clarifier des phrases... Ce mécanisme est une étrange bestiole)

Roger Orr observe que la spécification est exprimée sous la forme « ...comme des appels successifs à std::fgetc() » or cette fonction fait des transformations pour la paire CR+LF ce qui ne traduit pas l'intention. JeanHeyd Meneide dit que l'idée est de traiter la ressource comme un fichier binaire, ce qui évite cet enjeu, or le texte ne le dit pas. On corrige

L'interaction entre les macros et #embed est examinée en détail (on peut construire des noms de fichiers par des macros, par exemple). On s'aperçoit en chemin que le concept de ressource vide n'est pas explicitée dans le texte, ce qui peut causer de la confusion (en particulier si on tient compte que #embed peut être accompagné de if_empty(val) pour un plan B).

On revoit cette proposition demain. Là, c'est le temps d'aller faire dodo.

Jour 4 – 14 février 2025

Je ne ferai qu'acte de présence aujourd'hui car je dois rencontrer mes groupes de finissants au Collège et je ne les verrai que trois fois, alors manquer l'une de ces fois n'est pas vraiment une option.

P1967R13 – #embed - a scannable, tooling-friendly binary resource inclusion mechanism

Au début des travaux, on réagit à un problème soulevé dans les dernières heures par l'implémentation de #embed chez gcc. Lors de l'expansion des macros, on a relevé des problèmes importants avec le comportement de ce nouveau mécanisme tel que spécifié. JeanHeyd Meneide propose des ajustements au texte proposé dans le but de contourner ces problèmes, surtout avec defined(MACRO) et __has_embed(RES). Hubert Tong demande si __has_include a les mêmes problèmes (dans le moment, __has_include(FILE) peut être 0 ou 1, et être utilisé comme limit() de #embed comme le peut defined(MACRO) ce qui pose des problèmes importants).

Jason Merrill explique que le coeur de l'enjeu est qu'il faut se rendre jusqu'à la fin de la ligne pour savoir ce qui doit être étendu (expanded) dans les noms de macros, ce qui est un petit cauchemar, en particulier si on tient comptes des extensions selon les vendeurs. La proposition faite par l'implémenteur de son équipe est de simplement faire l'expansion de toutes les macros après #embed (c'est moins monstrueux comme travail). Il se trouve que le texte est copié pour l'essentiel de celui de #include mais ce dernier est moins sensible (ce qui complique #embed est l'ajout de paramètres comme limit()).

Évidemment, il faut garder le langage C dans la boucle puisque ce mécanisme fait déjà partie de C23 (mais heureusement, JeanHeyd Meneide est leur Project Editor en ce moment!). Il faudra passer par EWG pour le changement de design quant aux expansions de macros, puis revenir à CWG (idéalement aujourd'hui).

(on discute ensuite des trivial union; semble qu'il y ait eu beaucoup de trafic sur le sujet dans les différents canaux de discussion, mais que la revue formelle de la proposition n'ait pas été faite parce que des bogues ont été découverts)

P3533 – constexpr virtual inheritance

On sonde rapidement les implémenteurs dans la salle à ce sujet. Ça semble moins préoccupant que les coroutines constexpr, mais celles-ci ont été mises de côté pour le moment (faute de ressources).

Core Issue 2990. Exporting redeclarations of namespaces

Ceci a été corrigé dernièrement :

export module M;
namespace N { // external linkage, attached to global module, not exported
  void f();
}
namespace N { // error: exported namespace, redeclares non-exported namespace
  export void g();
}

... mais le correctif a causé ceci :

module;
#include "header"
export module wrap;

export using ::feature;               // already allowed previously
export extern "C++" void feature();   // newly allowed by CWG2921

Le correctif proposé est tout petit et semble acceptable.

D2843 – Remove UB from preprocessor

Cette proposition retire les occasions de UB des diverses clauses du préprocesseur et les remplace par des cas de ill-formed. C'est fascinant de voir le nombre de cas obscurs qui pouvaient, pour une implémentation hostile, avoir des effets délétères sur un programme lors de la compilation, avant-même l'avènement d'une intervention du compilateur lui-même.

On trace un lien avec les problèmes soulevés dans le cas de #embed plus tôt avec les macro expansions. On pense aux macros dont le résultat de l'expansion résulte en des noms de macros. Par exemple :

#define DEF(M) defined ( M )
#define THIS_MACRO XXX
#if DEF(THIS_MACRO)
...   // not reached, because XXX is not defined
#endif

On vérifie et ça fonctionne! Hubert Tong suggère cette alternative :

#define DEF(X) defined(X)
#define what hi
#define hi hi

#if DEF(what)
#error
#endif

... qui fonctionne aussi (ici, on a l'erreur mais c'est ce qui est souhaité). Ou encore (https://godbolt.org/z/sKMY31av4) :

#define DEF(M) defined ( M )
#define THIS_MACRO XXX
#if DEF(THIS_MACRO)
#error ":)" // no compiler errors here
#endif

Un paragraphe est ajouté à la section sur les expansions de macros (il vient d'ailleurs dans le langage, plus précisément du Library Text pour une raison étrange, alors on les consultera par courtoisie). J'apprends que likely et unlikely ont un traitement spécial dans le cas des macros, pour des raisons historiques je suppose.

On a un problème avec certaines chaînes de caractères (une discussion de l'effet des remplacements de caractères précédés par un \ par un groupe d'experts est extrêmement divertissant). Il faudra de petites retouches pour éviter une lecture oblique (et potentiellement hostile) des règles.

(brève pause à 4 h 15 heure de Montréal)

P2786R13 – Trivial Relocatability for C++26

On revient sur la question des union contenant un type polymorphique, car il existe des plateformes pour lesquelles les vtbl ne sont pas memcpy()-able. La recommandation de EWG est de faire en sorte que la copyabilité soit alors implementation-defined. On peut donc poursuivre les travaux, cet aspect étant dorénavant mentionné dans les clauses décrivant ce qui fait qu'un type est eligible for trivial relocation.

On remarque un cas de type trivialement relocalisable qui a été oublié dans la proposition.

L'enjeu de l'effet d'une relocalalisation triviale a été traité par l'ajout de mots expliquant que les métadonnées quant aux types (je paraphrase) des objets source et destination peuvent différer. Ceci vise à permettre de contourner l'enjeu de la duplication d'un pointeur sur une vtbl.

Après un peu de travail, on demande à LWG de jeter un coup d'oeil à sa section, mais on pense l'amener pour vote demain.

On jongle avec l'idée de traiter ensuite P0149 – Generalized member pointers, mais on ne l'a pas vu cette semaine encore et on préfère traiter les trucs susceptibles d'être portés pour votre demain.

D2841 – concept and variable template parameters

C'est une proposition examinée plus tôt cette semaine. On fait la revue des changements qui y ont été apportés. Sur le plan grammatical, on parle souvent d'éliminer des restrictions ou des cas particuliers alors, de manière amusante, c'est parfois une simplification. On ajoute toutefois l'idée de concept-dependent à celles de type-dependent et de value-dependent.

On examine les exemples. Plusieurs sont très arides, car on définit des formes normales ou canoniques pour comparer des abstractions et définir des règles de subsomption, mais il y en a des très chouettes aussi. Par exemple :

template <typename T, template <typename> concept>
  struct wrapper{};
template <typename... T, template <typename> concept... CTs>
  int f(wrapper<T, CTs>...) requires (CTs<T> && ...); // erreur : on n'a pas de concepts à ce stade, on ne sait pas combien il y en aura non plus

On réévaluera peut-être ce cas dans le futur. C'est du bon travail. Ça s'en va au vote demain.

(je dois quitter... pour aller travailler!)

Jour 5 – 15 février 2025

La plénière débute vers 2 h 30 du matin heure de Montréal, 8 h 30 heure de Hagenberg. J'ai dormi deux heures environ (mon amoureuse Za et moi sommes allés voir un excellent spectacle – Klô Pelgag – à la Petite église, une salle de spectacles de St-Eustache là où j'habite, puis nous nous sommes occupés des lapins et j'ai fait une brève sieste). Je ferai ma vraie nuit après les votes.

Je prends d'abord quelques minutes pour vérifier l'état de quelques-unes des propositions amenées pour vote ce matin et qui auraient pu être modifiées au cours de la semaine qui se termine. Ce fut (ma foi!) une semaine productive, et certains aspects importants du langage prendront du coffre aujourd'hui, quels que soient les résultats des votes.

John Spicer et Herb Sutter nous accueillent. Herb Sutter souligne la quantité d'ouvrage abattu au cours des derniers jours (avec raison!), malgré la St-Valentin.

Exceptionnellement, EWG présente en premier car le Chair de ce groupe est à l'aéroport. EWG a vu 56 propositions et résolu 7 Core Issues. Le contrats ont progressé, le consensus a fortement progressé, on a retiré le support de contrats sur des fonctions membres virtuelles (pour le moment). On approchera les Profiles à travers un Language Safety White Paper car ils sont généralement vus comme critiques dans les délais de C++26, mais on n'arrivait pas à obtenir un consensus cette semaine. On vise toujours la réflexivité pour C++26, avec contrôle d'accès sur une base opt-in et réflexivité sur les paramètres. Le Pattern Matching a presque obtenu le consensus, mais ça va aller à C++29. Certains trucs controversés (« there are eight bits in a byte » et « chained comparisons ») n'ont pas passé la barre.

Votes proposés par EWG

Exceptionnellement, EWG amène le vote suivant à l'attention du comité :

1. Change the ship vehicle for Transaction Memory TSv2 (N4923) from a TS to a white paper. Appoint Michael Wong as editor.

(unanime)

Rapports des groupes d'études

SG1: Concurrency and Parallelism Study Group : on a éliminé toute ce qui semblait bloquer la progression des senders / receivers pour C++26 et on a commencé à examiner de nouvelles propositions de senders / receivers en vue de C++29. On a relayé concurrent_queues<T>, traité des guarded objects et résolu des CWG issues et des LWG issues.

SG2: Modules Study Group : inactif cette semaine

SG3: File System Study Group : inactif cette semaine

SG4: Networking Study Group : on a examiné un design préliminaire basé sur les senders / receivers et ça semble prometteur. Nous ne ferons plus de Networking TS, préférant un autre véhicule.

SG5: Transactional Memory : voir plus haut

SG6: Numerics : une demi-journée de rencontre (plusieurs membres étaient malades ou pris ailleurs), mais on a tout de même traité toutes les propositions qui avaient des champions. Plusieurs dossiers en lien avec les nombres à virgule flottante ont progressé

SG7: Reflection : nous avons vu quatre propositions, dont une sur la réflexivité appliquée aux annotations (attributes) qui a été relayée à EWG.

SG8: Concepts : inactif cette semaine

SG9: Ranges : rencontre féconde où nous avons fait progresser plusieurs propositions (ça va trop vite pour prendre des notes, mais ça semble chouette)

SG10: Feature Test : inactif cette semaine

SG12: Undefined and Unspecified Behavior : inactif cette semaine

SG13: I/O : inactif cette semaine

SG14: Low Latency : pas de rencontre cette semaine mais on se rencontre souvent

SG15: Tooling : deux rencontres cette semaine. Avec le retrait du Ecosystem TS, on réfléchit à un nouveau véhicule (un Whitepaper semble tentant)

SG16: Unicode : inactif cette semaine mais on progresse

SG17: EWG Incubator : nous avons vu sept propositions, dont quatre relayées à EWG (incluant une sur les exceptions à coût nul). On a travaillé fort pour accompagner les présentatrices et les présentateurs

SG18: LEWG Incubator : inactif cette semaine

SG19: Machine Learning : pas de rencontre cette semaine mais on se rencontre souvent

SG20: Education : inactif cette semaine

SG21: Contracts : on a examiné quelques propositions pour post-C++26, incluant une proposition sur les contrats appliqués aux pointeurs de fonctions (c'est pas prêt) et un autre pour exiger une sémantique (observe, enforce ou autre). Nous nous rencontrons chaque semaine depuis longtemps et il y a beaucoup de participantes et de participants

SG22: C/C++ Liason : inactif cette semaine

SG23: Safety and Security : on a eu une journée de rencontre et trois propositions ont été relayées (une à LEWG et deux à EWG)

ABI Group : inactif cette semaine

Admin Group : il y a eu près de 200 participantes et participants cette semaine. Le prochain mailing sera le 17 mars (la Saint-Patrick). On aura un nouveau Wiki avec login amélioré pour Sofia

Rapports des groupes de travail

EWG : voir plus haut (horaire atypique pour cette fois)

LEWG : grosse semaine de travail. On fait un rappel des processus de vote électroniques, puis on discute des gros dossiers de la semaine incluant trivial relocatability, senders / receivers, standard library hardening ,concurrent_queue<T>, optional<T&>, formatting enums (et autres types avec format_as()), etc. Plusieurs autres dossiers sur la table, incluant l'amélioration des coroutines, un raffinement des processus du groupe, meilleur support d'Unicode, etc. (c'est une longue liste!)

CWG : on s'est rencontrés toute la semaine. Reflection n'est pas encore sur la table pour fins de vote, mais nous nous rencontrons chaque deux semaines et ça s'en vient. Nous avons fait une place substantielle aux contrats. Trois votes qui demandent de l'attention : #embed semblait prêt, mais des préoccupations ont été soulevées cette nuit par écrit. Puisque #embed est dans C23, je pense qu'on peut traiter ces préoccupations par des Core Issues. Dans le cas de trivial relocation, l'annexe C est incorrecte sur la base des règles ISO mais on peut peut-être les traiter de manière éditoriale. Enfin, trivial union préoccupe certaines personnes mais je pense qu'on peut procéder avec des Core Issues

LWG : grosse semaine avec SIMD, les ranges, les senders / receivers, Library Hardening, etc.

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 P3638R0 (Core Language Working Group "ready" Issues for the February, 2025 meeting) to the C++ Working Paper.

(unanime)

2. Apply the changes in P3542R0 (Abolish the term "converting constructor") to the C++ Working Paper.

(unanime)

3. Apply the changes in P3074R7 (trivial unions (was std::uninitialized)) to the C++ Working Paper.

Vote demandé. Consensus

4. Apply the changes in P1494R5 (Partial program correctness) to the C++ Working Paper.

(unanime)

5. Apply the changes in P2900R14 (Contracts for C++) to the C++ Working Paper.

Vote demandé. Consensus. Ouf, un gros, gros morceau!

6. Apply the changes in P3475R2 (Defang and deprecate memory_order::consume) to the C++ Working Paper.

(unanime)

7. Apply the changes in P2841R7 (Concept and variable-template template-parameters) to the C++ Working Paper.

Vote demandé. Consensus

 8. Apply the changes in P2786R13 (Trivial Relocatability For C++26) to the C++ Working Paper.

Vote demandé. Consensus

 9. Apply the changes in P1967R14 (#embed - a simple, scannable preprocessor-based resource acquisition method) to the C++ Working Paper.

Vote demandé. Consensus

Votes proposés par LWG

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

1. Apply the changes for all Tentatively Ready issues in P3615R0 (C++ Standard Library Ready Issues to be moved in Hagenberg, Feb. 2025) to the C++ working paper.

(unanime)

 2. Apply the changes in P2830R9 (Standardized Constexpr Type Ordering) to the C++ working paper.

On signale que CWG n'a pas vu ceci et que c'est dû à une bête confusion (LWG pensait que si). On se demande si on devrait attendre à Sofia pour le voter, question de laisser CWG y jeter un oeil. On convient unanimenent de retirer ce vote aujourd'hui et de le ramener cet été

3. Apply the changes in P3137R3 (views::to_input) to the C++ working paper.

(unanime)

4. Apply the changes in P0472R3 (Put std::monostate in <utility>) to the C++ working paper.

(unanime). On a repris ce vote pris à Wrocław parce que lors de cette rencontre, on avait mis à mauvaise version de la proposition au vote (accident)

 5. Apply the changes in P3349R1 (Converting contiguous iterators to pointers) to the C++ working paper.

(unanime)

6. Apply the changes in P3372R3 (constexpr containers and adaptors) to the C++ working paper.

(unanime)

7. Apply the changes in P3378R2 (constexpr exception types) to the C++ working paper.

(unanime)

8. Apply the changes in P3441R2 (Rename simd_split to simd_chunk) to the C++ working paper.

(unanime)

 9. Apply the changes in P3287R3 (Exploration of namespaces for std::simd) to the C++ working paper.

(unanime)

10. Apply the changes in P2976R1 (Freestanding Library: algorithm, numeric, and random) to the C++ working paper.

(unanime)

11. Apply the changes in P3430R3 (simd issues: explicit, unsequenced, identity-element position, and members of disabled simd) to the C++ working paper.

(unanime)

12. Apply the changes in P2663R7 (Interleaved complex values support in std::simd) to the C++ working paper.

(unanime)

13. Apply the changes in P2933R4 (Extend <bit> header function with overloads for std::simd) to the C++ working paper.

(unanime)

 14. Apply the changes in P2846R6 (reserve_hint: Eagerly reserving memory for not-quite-sized lazy ranges) to the C++ working paper.

Vote demandé. Consensus

15. Apply the changes in P3471R4 (Standard Library Hardening) to the C++ working paper.

Vote demandé. Consensus

16. Apply the changes in P0447R28 (Introduction of std::hive to the standard library) to the C++ working paper.

Quelqu'un demande s'il y a de l'expérience d'implémentation outre l'implémentation de référence. La réponse est deux implémentations partielles mais aucune préoccupation quant à l'implémentabilité.

Vote demandé. Consensus

17. Apply the changes in P3019R14 (indirect and polymorphic: Vocabulary Types for Composite Class Design) to the C++ working paper.

On signale que ce vote a été proposé dans le passé mais des problèmes avaient été trouvés avec la proposition, et ont été corrigés depuis.

Vote demandé. Consensus

(on prend une très brêve pause de dix minutes pour un café et on poursuit)

Autres rapports

Direction group : Michael Wong explique le rôle de ce groupe dans le contexte de P1000. On mentionne la retraite de Howard Hinnant, un individu exceptionnellement important dans l'évolution de C++. Il poursuit avec un discours sur l'importance de la sécurité en C++ et sur l'importance d'une intégration des contrats et des profils. Il mentionne que les propositions tendent à progresser plus lentement et qu'on souhaite améliorer la fluidité des processus. Enfin, il rappelle l'importance de traiter les collègues avec humanité.

On termine avec des remerciements aux Chairs, aux hôtes, aux scribes, et on présente Sofia et nos hôtes là-bas cet été (wg21.link/N5004). La rencontre suivante sera à Kona en novembre.

On ferme vers 5 h du matin heure de Montréal, et je vais aller faire dodo...


Valid XHTML 1.0 Transitional

CSS Valide !