OVH Cloud OVH Cloud

pre-Kona n1509 Generalized Initializer Lists

9 réponses
Avatar
Benoit Dejean
bonjour, je lis (et essaye de comprendre) très modestement certains
documents disponibles ici
http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/#pre_kona

j'ai une question à propos du n1509 Generalized Initializer Lists page
12: je n'arrive pas à comprendre l'exemple de problème avec le
constructeur de vector. Pourquoi est-ce en fait une déclaration de
fonction ?

merci beaucoup

9 réponses

Avatar
Gabriel Dos Reis
Benoit Dejean writes:

| bonjour, je lis (et essaye de comprendre) très modestement certains
| documents disponibles ici
| http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/#pre_kona
|
| j'ai une question à propos du n1509 Generalized Initializer Lists page
| 12: je n'arrive pas à comprendre l'exemple de problème avec le
| constructeur de vector. Pourquoi est-ce en fait une déclaration de
| fonction ?

C'est en fait un héritage (aggravé) de C.

Dans la grammaire C++, il y a une ambiguité entre une déclaration et
une expression. Pour lever cette ambiguité, la norme dit que si
quelque chose ressemble à une déclaration, a le goût d'une déclaration,
a l'odeur d'une déclaration, alors c'est une déclaration.

Dans l'exemple en question

vector<int> v(istream_stream<int>(cin), istream_stream<int>());

on a

(1) un type-specifier : vector<int>
(2) un declarator : v(istream_stream<int>(cin), istream_stream<int>())
Ce declarator a le goût d'un déclarator d'une fonction. En effet
"istream_stream<int>(cin)" peut être interpêté comme une
déclaration (de paramètre) -- eh oui, il est permis de mettre des
parenthèse infectes inutiles dans une déclaration; merci C ! -- et
"istream_stream<int>()" peut être interpreté comme une
déclaration de paramètre (non nommé).

On a tous les ingrédients en place pour penser qu'il s'agit d'une
déclaration. Donc, en vertu de la reglémentation en vigueur, on
obtient bien une déclaration d'une fonction nommée v qui prend deux
istream_stream<int> et retourne un vector<int>.

On pourait faire un passage en force en interdisant les déclarations
de fonctions dans une portée locale, maie cela casserait du code et ne
ressoudrait pas le problème -- imagine ce qui se passe dans la portée
globale.

-- Gaby
Avatar
Benoit Dejean
Le Fri, 03 Oct 2003 10:42:37 +0200, Gabriel Dos Reis a écrit :

Benoit Dejean writes:



C'est en fait un héritage (aggravé) de C.


je ne compte plus les « ugly » dans mes lectures... merci pour ta très

bonne explication

On pourait faire un passage en force en interdisant les déclarations de
fonctions dans une portée locale, maie cela casserait du code et ne
ressoudrait pas le problème -- imagine ce qui se passe dans la portée
globale.


donc si je saisis bien les Generalized Initializer Lists en plus
d'apporter un agrément d'écriture donneraient une solution/amélioration
à ce problème.

Avatar
Gabriel Dos Reis
Benoit Dejean writes:

| > On pourait faire un passage en force en interdisant les déclarations de
| > fonctions dans une portée locale, maie cela casserait du code et ne
| > ressoudrait pas le problème -- imagine ce qui se passe dans la portée
| > globale.
|
| donc si je saisis bien les Generalized Initializer Lists en plus
| d'apporter un agrément d'écriture donneraient une solution/amélioration
| à ce problème.

complètement.

En réalité, on fait encore mieux.

Condisère

struct T { /* ... */ };

struct A {
explicit A(bool);
operator void*();
};

bool has_feature(T);

int main()
{
if (A a = has_feature(T())); // #1
// ...
}

la ligne #1 est une erreur parce que le constructeur de A qui accepte
un bool ext explicit. La syntaxe

if (A a(has_feature(T())))

n'est pas permise. Et même si elle etait permise, elle ne ferait pas
la bonne chose. Par contre, la nouvelle syntaxe que nous proposons
permet d'écrire cela comme

if (A a = { has_feature(T()) })

-- Gaby
Avatar
Benoit Dejean
Le Fri, 03 Oct 2003 11:17:36 +0200, Gabriel Dos Reis a écrit :

Benoit Dejean writes:

complètement.

En réalité, on fait encore mieux.

Condisère

struct T { /* ... */ };

struct A {
explicit A(bool);
operator void*();
};

bool has_feature(T);

int main()
{
if (A a = has_feature(T())); // #1
// ...
}

la ligne #1 est une erreur parce que le constructeur de A qui accepte un
bool ext explicit. La syntaxe

if (A a(has_feature(T())))

n'est pas permise. Et même si elle etait permise, elle ne ferait pas
la bonne chose. Par contre, la nouvelle syntaxe que nous proposons
permet d'écrire cela comme

if (A a = { has_feature(T()) })


intéressant, je ne savais qu'en présence d'explicit, l'initialisation
avec = n'avait pas le même sens. voir plus #1

Tout ça est très bien. Est-ce que vous avez la volonté d'apporter cette
nouveauté pour résoudre ce genre de problème (toujours ne plus de la
facilité d'écriture) ou bien vous aimeriez la généraliser pour un
emploi très courant ?


#1

dans ce cas là

struct Foo
{
Foo()
{ }

explicit Foo(int)
{ }

Foo& operator=(const Foo &dummy)
{ return *this; }

Foo& operator=(int)
{ return *this; }
};


Foo b = 3;

ne devrait pas être résolue comme la construction par défaut, suivi de
l'affectation ?

j'ai peur de ne pas bien comprendre le sens l'initialisation avec =. Si
ton exemple ne fonctionne pas, c'est bien que ce n'est pas équivalent à
l'appel parenthésé au constructeur ... mais au fil que j'écris je
commence à comprendre. L'initialisation avec = n'est correcte que si la
partie droite est de type Foo, quitte à être converti implicitement pour
y arriver. c'est à peu près cela ?

Avatar
Gabriel Dos Reis
Benoit Dejean writes:

[...]

| > n'est pas permise. Et même si elle etait permise, elle ne ferait pas
| > la bonne chose. Par contre, la nouvelle syntaxe que nous proposons
| > permet d'écrire cela comme
| >
| > if (A a = { has_feature(T()) })
|
| intéressant, je ne savais qu'en présence d'explicit, l'initialisation
| avec = n'avait pas le même sens. voir plus #1

C'est le sens même d'explicit :-)

| Tout ça est très bien. Est-ce que vous avez la volonté d'apporter cette
| nouveauté pour résoudre ce genre de problème (toujours ne plus de la
| facilité d'écriture) ou bien vous aimeriez la généraliser pour un
| emploi très courant ?

hmm, là je ne comprends pas très bien ce que tu veux dire.
Nous proposons que A a = { e } soit équivalent à une direct
initialization. Et cela couvre le cas que j'ai mentionné.

| #1
|
| dans ce cas là
|
| struct Foo
| {
| Foo()
| { }
|
| explicit Foo(int)
| { }
|
| Foo& operator=(const Foo &dummy)
| { return *this; }
|
| Foo& operator=(int)
| { return *this; }
| };
|
|
| Foo b = 3;
|
| ne devrait pas être résolue comme la construction par défaut, suivi de
| l'affectation ?

Non. Cela a toujours voulu dire une copy-initialization et cela le
restera.

| j'ai peur de ne pas bien comprendre le sens l'initialisation avec =. Si
| ton exemple ne fonctionne pas, c'est bien que ce n'est pas équivalent à
| l'appel parenthésé au constructeur ... mais au fil que j'écris je
| commence à comprendre. L'initialisation avec = n'est correcte que si la
| partie droite est de type Foo, quitte à être converti implicitement pour
| y arriver. c'est à peu près cela ?

L'écriture

Foo b = 3 ; // #1

est une copy-initialization, à contraster avec

Foo b(3); // #2

qui est une direct-initailization.

Dans une initialisation par copie, on commence d'abord par convertir
l'expression d'initialisation en un Foo en appelant un constructeur de
conversion. Cela va créer un temporaire, et ce temporaire est utilisé
pour initialiser b en appelant le constructeur de copie.
S'il n'existe aucun constructeur de conversion (comme c'est le cas
ici) accessible, alors l'initialisation échoue. Si le constructeur par
copie échoue alors l'initialisation échoue.

L'initialisation directe ne requiert pas un constructeur de copie. Il
lui faut juste un bon constructeur (pas nécessairement de conversion).

Note que, dans le cas d'initialisation par copie, beaucoup de
compilateurs n'appellent pas le constructeur de copie -- ils se
contentent juste de vérifier qu'il est accessible -- et initialisent
directement. C'est permis.

-- gaby
Avatar
Benoit Dejean
Le Fri, 03 Oct 2003 11:55:43 +0200, Gabriel Dos Reis a écrit :

Benoit Dejean writes:

|
| intéressant, je ne savais qu'en présence d'explicit,
l'initialisation | avec = n'avait pas le même sens. voir plus #1

C'est le sens même d'explicit :-)


j'ai des lacunes


| Tout ça est très bien. Est-ce que vous avez la volonté d'apporter
cette | nouveauté pour résoudre ce genre de problème (toujours ne
plus de la | facilité d'écriture) ou bien vous aimeriez la
généraliser pour un | emploi très courant ?

hmm, là je ne comprends pas très bien ce que tu veux dire. Nous
proposons que A a = { e } soit équivalent à une direct initialization.
Et cela couvre le cas que j'ai mentionné.


ok

| ne devrait pas être résolue comme la construction par défaut, suivi
| de l'affectation ?

Non. Cela a toujours voulu dire une copy-initialization et cela le
restera.


j'ai de grosses lacunes.

| j'ai peur de ne pas bien comprendre le sens l'initialisation avec =.
Si | ton exemple ne fonctionne pas, c'est bien que ce n'est pas
équivalent à | l'appel parenthésé au constructeur ... mais au fil
que j'écris je | commence à comprendre. L'initialisation avec = n'est
correcte que si la | partie droite est de type Foo, quitte à être
converti implicitement pour | y arriver. c'est à peu près cela ?

L'écriture

Foo b = 3 ; // #1

est une copy-initialization, à contraster avec

Foo b(3); // #2

qui est une direct-initailization.

Dans une initialisation par copie, on commence d'abord par convertir
l'expression d'initialisation en un Foo en appelant un constructeur de
conversion. Cela va créer un temporaire, et ce temporaire est utilisé
pour initialiser b en appelant le constructeur de copie. S'il n'existe
aucun constructeur de conversion (comme c'est le cas ici) accessible,
alors l'initialisation échoue. Si le constructeur par copie échoue
alors l'initialisation échoue.

L'initialisation directe ne requiert pas un constructeur de copie. Il
lui faut juste un bon constructeur (pas nécessairement de conversion).

Note que, dans le cas d'initialisation par copie, beaucoup de
compilateurs n'appellent pas le constructeur de copie -- ils se
contentent juste de vérifier qu'il est accessible -- et initialisent
directement. C'est permis.


ce que je constate. merci beaucoup pour toutes tes explications.

Avatar
Benoit Dejean
Le Fri, 03 Oct 2003 09:54:25 +0200, Benoit Dejean a écrit :

bonjour, je lis (et essaye de comprendre) très modestement certains
documents disponibles ici
http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/#pre_kona


et quid du N1493 03-0076 Braces Initialization Overloading

est ce que ça recoupe ? j'ai du mal à comprendre : d'autres de tes
papiers (je te tutoie si ça te dérange, dis le moi) et de Stroustrup se
font référence les uns aux autres, et cela me semble cohérent. mais
là: est ce que je ne comprends rien à rien ou bien vous travaillez un
peu tous un peu dans votre coin en petits groupes, et à chaque rencontre
vous vous mettez sur la gueule parce que vous découvrez que vous êtes
plusieurs à avoir travailler dans votre coin et que vous avez tous des
conclusions différentes :D ?

Avatar
Gabriel Dos Reis
Benoit Dejean writes:

| Le Fri, 03 Oct 2003 09:54:25 +0200, Benoit Dejean a écrit :
|
| > bonjour, je lis (et essaye de comprendre) très modestement certains
| > documents disponibles ici
| > http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/#pre_kona
|
| et quid du N1493 03-0076 Braces Initialization Overloading

je l'ai découvert lorsque la mailing a été publiée. Et c'est
embarrassant :-/

Daniel était présent à Oxford.
Je ne me rappelle plus des circonstances exactes, mais je crois que
c'est en discutant de sa proposition

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1467.pdf

que nous lui avions fait remarquer qu'une partie de ce qu'il dit est
déjà possible et que l'autre partie est justement une suggestion
(ES26) faite par Alex Stepanov -- que nous avions dicsutée la veille
ou le matin même. À cette occasion, Kevlin Henney était intervenu pour
suggérer qu'il suffisait de reprendre la syntaxe de C99 ; la non
généralité de cette suggestion a été remarquée par BS lui même et
d'autres personnes. BS a d'ailleurs poursuivi en disant ce qu'il
aimerait avoir comme sémantique. À l'époque, nous pensions que cela
serait dur -- avant qu'on se mette au travail en juillet dernier :-)

Mais je dois avouer qu'en travaillant sur les generalized initializer,
j'avais complètement oublié que Daniel avait soumis un papier. Je
crois que c'était le cas pour BS aussi (mais bien sûr je ne peux pas
parler en son nom).

| est ce que ça recoupe ?

Oui, il y a des parties qui se recoupent mais cela reprend
essentiellement les idées que BS avait émises lors de cette fameuse
discussion. Daniel n'a pas traité le point le plus épineux : celui de
la résolution de surcharge.

| j'ai du mal à comprendre : d'autres de tes
| papiers (je te tutoie si ça te dérange, dis le moi) et de Stroustrup se
| font référence les uns aux autres, et cela me semble cohérent. mais
| là: est ce que je ne comprends rien à rien ou bien vous travaillez un
| peu tous un peu dans votre coin en petits groupes, et à chaque rencontre
| vous vous mettez sur la gueule parce que vous découvrez que vous êtes
| plusieurs à avoir travailler dans votre coin et que vous avez tous des
| conclusions différentes :D ?

Non, on essaie de se chamailler *avant* la réunion :-)
(Les réunions coûtent suffisamment cher en ressources pour qu'on n'en
fasse pas n'importe quoi).

En fait, nous essayons de diffuser aussi largement que possible nos
intentions de faire quelque chose ainsi que ce que nous faisons --
justement pour éviter du gaspillage de ressources. Par exemple, nous
avions fait circuler des brouillons de cette proposition. Les experts
C/C++ de l'AFNOR avait vu/commenté des versions de ce papier en
Juillet dernier. Même chose sur le réflecteur du comité. Je présume
que Daniel ne doit pas être sur cette liste.

M'enfin, on verra à Kona comment le EWG va unifier les deux -- cela ne
devrait pas être difficile.

En ce qui concerne les références croisées, BS et moi sommes
convaincus que le langage ne doit pas être une somme de
fonctionnalités ; au contraire, ces dernières doivent tisser des liens
étroits entre elles pour faire quelque chose de cohérent et de
solide. Alors, à chaque fois, nous attachons une attention
particulière aux intéractions entre différentes propositions/suggestions.
BS appelle cela « language design » par opposition à « feature design ».
Regarde, par exemple, comment il lie la suggestion ES053 aux
generalized initializers dans la proposition pour user-defined literals.

Si nous avions les « concepts », il est probable que nous aurions
amérioré nombre de propositions y compris (et surtout) celles
concernant la bibliothèque. Mais nous avons eu quelque difficultés à
finir le papier à temps pour la deadline. Il sera sans doute dans la
mailing post-Kona.

Si tu veux avoir une idée des suggestions/propositions communiquées à
l'EWG, tu peux consulter

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1512.html

-- Gaby
Avatar
Benoit Dejean
Le Sat, 04 Oct 2003 10:25:28 +0200, Gabriel Dos Reis a écrit :

[...]

En ce qui concerne les références croisées, BS et moi sommes
convaincus que le langage ne doit pas être une somme de
fonctionnalités ; au contraire, ces dernières doivent tisser des liens
étroits entre elles pour faire quelque chose de cohérent et de solide.
Alors, à chaque fois, nous attachons une attention particulière aux
intéractions entre différentes propositions/suggestions. BS appelle
cela « language design » par opposition à « feature design ».
Regarde, par exemple, comment il lie la suggestion ES053 aux generalized
initializers dans la proposition pour user-defined literals.


c'est plus spécialement à celà que je faisais référence. Je trouve
cette approche très intelligente.

Si nous avions les « concepts », il est probable que nous aurions
amérioré nombre de propositions y compris (et surtout) celles
concernant la bibliothèque. Mais nous avons eu quelque difficultés à
finir le papier à temps pour la deadline. Il sera sans doute dans la
mailing post-Kona.

Si tu veux avoir une idée des suggestions/propositions communiquées à
l'EWG, tu peux consulter

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1512.html


comme d'habitude, grand merci.

Benoît