OVH Cloud OVH Cloud

membres d'une base dépendante ?

48 réponses
Avatar
Dimitri Papadopoulos-Orfanos
Bonjour,

Le code suivant n'est plus compilé par des compilateurs récents tels que
gcc 3.4 :

template <typename T> struct A {
int x;
};
template <typename T> struct B : public A<T> {
void foo() { x = 1; }
};

L'erreur est:
foo.cc: In member function `void B<T>::foo()':
foo.cc:5: error: `x' undeclared (first use this function)
foo.cc:5: error: (Each undeclared identifier is reported only once for each
function it appears in.)

Les notes de gcc 3.4 parlent bien de ce changement :
In a template definition, unqualified names will
no longer find members of a dependent base.

Toutefois je n'arrive pas à trouver le paragraphe du chapitre 14 de la
norme C++ qui le justifient. C'est probablement caché dans 14.6 mais
j'ai du mal à suivre les paragraphes en question... Quelqu'un peut-il me
montrer le paragraphe qui s'applique à ce cas ?

Qu'est-ce qu'une "base dépendante" ? Pourquoi faire un cas spécial pour
les templates ?

Merci d'avance,
Dimitri

10 réponses

1 2 3 4 5
Avatar
Gabriel Dos Reis
Dimitri Papadopoulos-Orfanos writes:

| Bonjour,
|
| Le code suivant n'est plus compilé par des compilateurs récents tels
| que gcc 3.4 :
|
| template <typename T> struct A {
| int x;
| };
| template <typename T> struct B : public A<T> {
| void foo() { x = 1; }
| };
|
| L'erreur est:
| foo.cc: In member function `void B<T>::foo()':
| foo.cc:5: error: `x' undeclared (first use this function)
| foo.cc:5: error: (Each undeclared identifier is reported only once for each
| function it appears in.)
|
| Les notes de gcc 3.4 parlent bien de ce changement :
| In a template definition, unqualified names will
| no longer find members of a dependent base.
|
| Toutefois je n'arrive pas à trouver le paragraphe du chapitre 14 de la
| norme C++ qui le justifient. C'est probablement caché dans 14.6 mais
| j'ai du mal à suivre les paragraphes en question... Quelqu'un peut-il
| me montrer le paragraphe qui s'applique à ce cas ?

14.6.2/3

| Qu'est-ce qu'une "base dépendante" ?

§§14.6.2.1, 14.6.2.2

| Pourquoi faire un cas spécial pour les templates ?

Spécialisation explicite.

-- Gaby
Avatar
kanze
Dimitri Papadopoulos-Orfanos wrote
in message news:<414939e3$0$15754$...

Le code suivant n'est plus compilé par des compilateurs récents tels
que gcc 3.4 :

template <typename T> struct A {
int x;
};
template <typename T> struct B : public A<T> {
void foo() { x = 1; }
};

L'erreur est:
foo.cc: In member function `void B<T>::foo()':
foo.cc:5: error: `x' undeclared (first use this function)
foo.cc:5: error: (Each undeclared identifier is reported only once for each
function it appears in.)

Les notes de gcc 3.4 parlent bien de ce changement :
In a template definition, unqualified names will
no longer find members of a dependent base.

Toutefois je n'arrive pas à trouver le paragraphe du chapitre 14 de la
norme C++ qui le justifient. C'est probablement caché dans 14.6 mais
j'ai du mal à suivre les paragraphes en question... Quelqu'un peut-il
me montrer le paragraphe qui s'applique à ce cas ?


Pas moi. J'avoue que je trouve le chapître 14 complétement
incompréhensible. En revanche, je te conseille fort le livre de
Vandevoorde et Josuttis -- c'est d'une claireté exemplaire.

Qu'est-ce qu'une "base dépendante" ?


Une base qui dépend d'un ou de plusieurs paramètres du template.

Pourquoi faire un cas spécial pour les templates ?


Pour créer la confusion ? Pour casser le code existante ? Pour emmerder
les gens en général ? :-)

Sérieusement, le problème, c'est qu'un template (aujourd'hui) est
« compilé » deux fois -- une fois quand on en rencontre sa définition,
et une seconde quand il est instantié. Or, quand on rencontre sa
définition, on ne sait rien de ces paramètres. Même dans le cas que tu
présentes, il peut y avoir une spécialisation de A qui ne contient pas
de x. Alors, quand le compilateur recontre un symbole lors de la
première compilation, il décide si ce symbole est « dépendant » ou non ;
si c'est dépendant, il suppose que ce n'est pas le nom d'un type (au
moins qu'on lui a dit le contraire), mais diffère le récherche du nom à
la seconde compilation. Tandis que s'il n'est pas dépendant, il fait la
recherche immédiatement, sans tenir compte de ce qui pourrait dépendre
d'un paramètre. S'il le trouve, il lie le nom à ce symbole pour
toujours -- si tu avais un autre i, global, ce serait cet i qui servira,
et non celui de la base, même si par la suite, il s'avère que la base a
bien un i. Et si l'autre i n'existe pas, c'est une erreur.

Quant à la motivation de cette bizarrerie, considérons le suivant:

#include <nath.h>

template< typename B >
class A : public B
{
void f( double d ) { double d = sin( d ) ; }
} ;

Je crois que c'est clair quelle fonction l'auteur voulait quand il a
écrit sin(d). Or, qu'est-ce qui se passe si la classe B comporte une
fonction sin() ? Dans le C++ classique, c'est la fonction de la classe
de base qui servira. Dans le C++ standard, c'est toujours la fonction
déclarée dans <math.h>.

Évidemment, aujourd'hui, dans le C++ standard, on écrira plutôt :

#include <cmath>

template< typename B >
class A : public B
{
void f( double d ) { double d = std::sin( d ) ; }
} ;

Et le problème ne se présentera pas. Même dans le C++ classique, on
aurait pû écrire ::sin(d) pour éviter le problème et cette pratique
était même assez répandue dans certains milieux. Mais elle était loin
d'être universelle, et je crois que l'idée des deux « compilations »
précède les namespaces, qui le rend superflu. N'empêche que l'idée de
base me semble bien -- seulement, je n'aime pas que ce soit le
compilateur (et non moi) qui choisit quels noms sont dépendants, et
quels noms ne le sont pas, d'une façon assez subtile et non toujours
très transparente.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Dimitri Papadopoulos-Orfanos
Bonjour,

Pourquoi faire un cas spécial pour les templates ?



Pour créer la confusion ? Pour casser le code existante ? Pour emmerder
les gens en général ? :-)


Effectivement, ce genre de plaisanterie casse des milliers de lignes de
code. C'est d'un goût douteux :-)


Quant à la motivation de cette bizarrerie, considérons le suivant:

#include <nath.h>

template< typename B >
class A : public B
{
void f( double d ) { double d = sin( d ) ; }
} ;

Je crois que c'est clair quelle fonction l'auteur voulait quand il a
écrit sin(d). Or, qu'est-ce qui se passe si la classe B comporte une


Ben dans mon cas, ce serait plutôt B::sin(), et j'ai ici des centaines
de lignes de code qui ont été écrites dans ce sens. Je les ai
transformées en rajoutant 'this->' mais ça a le désavantage de rendre le
code illisible. Par exemple ceci :
_array[_x][_i]
se transforme en:
this->_array[this->_x][this->_i]
ou
B::_array[B::_x][B::_i]
et j'ai en stock des lignes de code plus compliquées... Pour que le
nouveau code reste lisible et maintenable, il faudrait complétement
réécrire des centaines de classes. Chose que je ne peux pas faire. Je
pense que genre de changements met en cause la pertinence du C++ pour
l'écriture de gros projets destinés à vivre plusieurs années.

--
Dimitri


Avatar
Gabriel Dos Reis
Dimitri Papadopoulos-Orfanos writes:

| Bonjour,
|
| >>Pourquoi faire un cas spécial pour les templates ?
| > Pour créer la confusion ? Pour casser le code existante ? Pour
| > emmerder
| > les gens en général ? :-)
|
| Effectivement, ce genre de plaisanterie casse des milliers de lignes
| de code. C'est d'un goût douteux :-)

Évidemment, James -- malgré les faits -- essayera de présenter ces
règles comme si elles dataient d'hier.

Mais je suis encore loin de croire que c'est un cas désespéré.

-- Gaby
Avatar
Gabriel Dos Reis
Dimitri Papadopoulos-Orfanos writes:

| réécrire des centaines de classes. Chose que je ne peux pas faire. Je
| pense que genre de changements met en cause la pertinence du C++ pour
| l'écriture de gros projets destinés à vivre plusieurs années.

Ces règles n'ont pas été inventées hier. Elles datent du temps même de
la conception des templates. Certaines personnes (avec le complice de
certains compilateurs) essayeront de te faire croire que c'est pas vrai.

Google pour des messages de David Vendevoorde et moi même sur ce
sujet.

-- Gaby
Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
Dimitri Papadopoulos-Orfanos writes:

| >>Pourquoi faire un cas spécial pour les templates ?
| > Pour créer la confusion ? Pour casser le code existante ? Pour
| > emmerder les gens en général ? :-)

| Effectivement, ce genre de plaisanterie casse des milliers de lignes
| de code. C'est d'un goût douteux :-)

Évidemment, James -- malgré les faits -- essayera de présenter ces
règles comme si elles dataient d'hier.


Dans ton imagination, peut-être. Où est-ce que tu vois la moindre
indication sur l'origine des règles ?

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
Dimitri Papadopoulos-Orfanos
writes:

| réécrire des centaines de classes. Chose que je ne peux pas faire.
| Je pense que genre de changements met en cause la pertinence du C++
| pour l'écriture de gros projets destinés à vivre plusieurs années.

Ces règles n'ont pas été inventées hier.


Qu'importe quand elles ont été inventées. Elles ne sont pas
particulièrement intuitives. Surtout, elles représentent un changement
par rapport à ce que les compilateurs faisaient jusqu'il y a peu. (Les
bons compilateurs ont des options pour supporter du code ancien. Les
très bons auraient même une stratégie de migration définie pour
l'utilisation. Mais si j'utilise le conditionnel ci-dessus, il y a bien
une raison ; je ne connais pas d'aussi bon.)

Elles datent du temps même de la conception des templates.


Tu veux dire comme au temps de l'ARM ? Ou qu'elles étaient implémentées
dans CFront 3.0 ? N'exagérons rien.

La situation est complexe. L'idée d'utiliser une recherche à deux temps
est apparue assez vite (2-3 ans ?) après les premières implémentations
des templates, et bien avant la plupart des implémentations. Je crois
que l'intention d'imposer une recherche à deux temps est apparue assez
tôt dans le groupe de travail qui s'occupait des templates dans le
comité de normalisation. Ce qui veut dire que les implémenteurs des
compilateurs en étaient probablement au courants, au moins pour la
plupart. Ils ont effectivement choisi de l'ignorer, de façon à ce que
leurs utilisateurs aient davantage de problèmes maintenant.

Pour monsieur tout le monde, évidemment, les templates, c'était ce que
faisait CFront, étant donné que c'était le seul compilateur qui les
implémentait. Pendant longtemps, d'ailleurs, ce que faisait CFront
faisait figure de norme pour les utilisateurs et les autres
implémenteurs. Jusqu'au point d'en dupliquer les bugs. Même aujourd'hui,
certains compilateurs conforme (exprès) plus à ce que faisait CFront
qu'à la norme.

Certaines personnes (avec le complice de certains compilateurs)
essayeront de te faire croire que c'est pas vrai.


Tu peux montrer qui, et où ?

Je dirais plutôt que certaines personnes cherchent à détourner
l'argument sur l'histoire de l'idée, plutôt que de régarder la réalité
des faits, c-à-d qu'il y a une quantité de code importante qui a été
écrite selon d'autres règles, plus simples et plus intuitives, et qu'au
fur et à mésure que les compilateurs implémentent les règles de la
norme, ce code se casse. Et que les programmeurs auteurs de ce code ne
comprenent pas toujours pourquoi, ni ce qu'il faut faire pour qu'il
marche.

C'est un problème réel pour quiconque travaille dans le monde
professionnel, où on ne peut pas se permettre de réécrire les
applications entières simplement parce qu'on a fait une mise à jour du
compilateur.

Google pour des messages de David Vendevoorde et moi même sur ce
sujet.


En ce qui concerne le sujet qui nous intéresse, c-à-d comment gérer la
transition, je n'ai jamais vu de posting ni de toi ni de David à ce
sujet. En revanche, David et Niko en parlent dans leur livre (que je
conseille très fortement à quiconque qui veut faire quoique ce soit avec
des templates) ; ils le reconnaissent comme problème.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Samuel Krempp
le Friday 17 September 2004 08:47, écrivit :
N'empêche que l'idée de
base me semble bien -- seulement, je n'aime pas que ce soit le
compilateur (et non moi) qui choisit quels noms sont dépendants, et
quels noms ne le sont pas, d'une façon assez subtile et non toujours
très transparente.


en l'occurence, pour rendre le nom dépendant, on a le choix entre :

        template <typename T> struct B : public A<T> {
typedef A<T> base_type; // dependant base
          void foo() { base_type::x = 1; }
        };

et
        template <typename T> struct B : public A<T> {
          void foo() { this->x = 1; }
        };
, non ?

y-a-t'il des arguments pour préferer l'un ou l'autre ?
(j'aurais tendance à prendre la 2° façon, plus courte et qui ne dit que ce
qu'il faut : il s'agit d'un membre)

--
Sam

Avatar
Gabriel Dos Reis
writes:

| Gabriel Dos Reis wrote in message
| news:...
| > Dimitri Papadopoulos-Orfanos writes:
|
| > | >>Pourquoi faire un cas spécial pour les templates ?
| > | > Pour créer la confusion ? Pour casser le code existante ? Pour
| > | > emmerder les gens en général ? :-)
|
| > | Effectivement, ce genre de plaisanterie casse des milliers de lignes
| > | de code. C'est d'un goût douteux :-)
|
| > Évidemment, James -- malgré les faits -- essayera de présenter ces
| > règles comme si elles dataient d'hier.
|
| Dans ton imagination, peut-être.

Bah non, je travaille pour celui qui a inventé les templates et
envisagé la recherche des noms en deux phases et a décrit cela
dans le papier dont je t'ai donné les références à plusieurs reprises
et aussi en parle dans son bouquin D&E.

| Où est-ce que tu vois la moindre
| indication sur l'origine des règles ?

Là où je travaille.

-- Gaby
Avatar
Gabriel Dos Reis
writes:

| Gabriel Dos Reis wrote in message
| news:...
| > Dimitri Papadopoulos-Orfanos
| > writes:
|
| > | réécrire des centaines de classes. Chose que je ne peux pas faire.
| > | Je pense que genre de changements met en cause la pertinence du C++
| > | pour l'écriture de gros projets destinés à vivre plusieurs années.
|
| > Ces règles n'ont pas été inventées hier.
|
| Qu'importe quand elles ont été inventées.

Cela importe parce que l'histoire de cette règle fait partie de la
confusion et de ses conséquences.

| Elles ne sont pas particulièrement intuitives.

« intuitives » est une question d'opinion, et non une vérité.
Je ne me fierais pas à ton intuition -- je me méfies déjà de la
mienne.

| Surtout, elles représentent un changement
| par rapport à ce que les compilateurs faisaient jusqu'il y a peu.

On a eu ce débat plusieurs fois. À chaque fois, tu répètes les mêmes
choses et à chaque fois tu dois te faire corriger. Par moi, ou par
David Vendevoorde. Je ne désespère pas qu'un jour cela va rentrer.

Les compilateurs ont choisi d'ignorer la règle, cela ne veut pas dit
qu'elle date d'hier. Je t'ai déjà donné des références publiques
remontant au moins à 1992, qui montrent que la notion de recherche en
deux phases étaient considérées bien avant qu'on ait eu les aspects
les plus avancés des templates.

| (Les
| bons compilateurs ont des options pour supporter du code ancien. Les
| très bons auraient même une stratégie de migration définie pour
| l'utilisation. Mais si j'utilise le conditionnel ci-dessus, il y a bien
| une raison ;

Oui, c'est que tu aimes digresser.

| je ne connais pas d'aussi bon.)
|
| > Elles datent du temps même de la conception des templates.
|
| Tu veux dire comme au temps de l'ARM ? Ou qu'elles étaient implémentées
| dans CFront 3.0 ? N'exagérons rien.

Ce que tu ne sais pas, c'est que les templates dans CFront ne sont pas
implémentés par son concepteur, ni par le « maintainer officiel. »
Mais par un utilisateur C++ qui avait lu certaines descriptions.
L'implémentation qui était livrée avec CFront ne contient pas tout ce
que le concepteur des templates envisageait.

| La situation est complexe. L'idée d'utiliser une recherche à deux temps
| est apparue assez vite (2-3 ans ?) après les premières implémentations
| des templates, et bien avant la plupart des implémentations.

Tu doutes que je travaille pour celui qui a conçu les templates, que
je travaille tous les jours sur les templates avec celui qui les a
conçus et qu'on discute quotidiennement des points techniques,
non-techniques et de son histoire ; et donc que j'ai accès à
l'information de première main que les allégations très approximatives
que racontes ?

| Je crois
| que l'intention d'imposer une recherche à deux temps est apparue assez
| tôt dans le groupe de travail qui s'occupait des templates dans le
| comité de normalisation.

Tu racontes cela comme si tu y étais, alors même que tu ne savais pas
que cela existait jusqu'à ce que je te montre le papier en question et
que tu me répondes quelque chose du genre « eh bin, peut-être qu'ils
en parlaient, mais moi je n'étais pas dans ce groupe, et puis de toute
façon, même ceux qui savaient n'en parlaient pas, et puis j'ai raison. »
<G>.

| Ce qui veut dire que les implémenteurs des
| compilateurs en étaient probablement au courants, au moins pour la
| plupart. Ils ont effectivement choisi de l'ignorer, de façon à ce que
| leurs utilisateurs aient davantage de problèmes maintenant.

Et David Vandevoorde t'a raconté son expérience personnelle de
l'époque où il travaillait sur le compilateur d'HP. Ils avaient
implémenté la règle en question vers 1997 ; après des tests sur des
programmes, ils avaient décidé de désactiver.

Et comme David le rappelle à chaque fois, cette règle est discutée dans D&E.

| Pour monsieur tout le monde, évidemment, les templates, c'était ce que
| faisait CFront, étant donné que c'était le seul compilateur qui les
| implémentait. Pendant longtemps, d'ailleurs, ce que faisait CFront
| faisait figure de norme pour les utilisateurs et les autres
| implémenteurs. Jusqu'au point d'en dupliquer les bugs. Même aujourd'hui,
| certains compilateurs conforme (exprès) plus à ce que faisait CFront
| qu'à la norme.
|
| > Certaines personnes (avec le complice de certains compilateurs)
| > essayeront de te faire croire que c'est pas vrai.
|
| Tu peux montrer qui, et où ?

Ben lis tes deux messages, je n'ai pas besoin d'aller chercher plus
loin. Ou fais un google pour tes messages dans ce groupe où toi et moi
en avons discuté, ou dans comp.lang.c++.moderated ou comp.std.c++ où
David Vandevoorde était intervenu.

[...]

| > Google pour des messages de David Vendevoorde et moi même sur ce
| > sujet.
|
| En ce qui concerne le sujet qui nous intéresse,

En parlant de diversion massive, tu es plutôt champion.
Relis le message auquel je répondais et auquel tu as cru devoir
répondre.

-- Gaby
1 2 3 4 5