OVH Cloud OVH Cloud

spécialisation et namespaces

11 réponses
Avatar
Cyril Poupon
Bonjour,

Le morceau de code suivant ne compile pas avec le compilateur GCC 3.4.2. Il
compile cepedant avec les compilateurs de Sun, SGI et GCC 3.3 et 3.5. Je me
demdande donc si c'est un bug du compilateur ou une nouvelle subtilité de
la norme C++ :

namespace nmr {
template <class T> void helper();
}
template <class T> void nmr::helper() {
}
template <> void nmr::helper<char>() {
}


Le message d'erreur est :

foo.cc:7: error: specialization of `template<class T> void nmr::helper()' in
different namespace
foo.cc:5: error:   from definition of `template<class T> void nmr::helper()'

--
Cyril

10 réponses

1 2
Avatar
Jean-Marc Bourguet
Cyril Poupon writes:

Bonjour,

Le morceau de code suivant ne compile pas avec le compilateur GCC 3.4.2. Il
compile cepedant avec les compilateurs de Sun, SGI et GCC 3.3 et 3.5. Je me
demdande donc si c'est un bug du compilateur ou une nouvelle subtilité de
la norme C++ :

namespace nmr {
template <class T> void helper();
}
template <class T> void nmr::helper() {
}
template <> void nmr::helper<char>() {
}


Le message d'erreur est :

foo.cc:7: error: specialization of `template<class T> void nmr::helper()' in
different namespace
foo.cc:5: error:   from definition of `template<class T> void nmr::helper()'


Accepter le code m'a l'air d'un bug. Mais ce qui m'etonne c'est la
regression dans gcc (pas fixe, fixe, pas fixe). Pour info,

http://www.comeaucomputing.com/pcgi-bin/compiler.html

Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
Copyright 1988-2003 Comeau Computing. All rights reserved.
MODE:strict errors C++

"ComeauTest.c", line 6: error: the initial explicit specialization of function
"nmr::helper<T>() [with T=char]" must be declared in the namespace
containing the template
template <> void nmr::helper<char>() {
^

1 error detected in the compilation of "ComeauTest.c".

J'ai pas le temps de verifier les sources.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Cyril Poupon
Bonjour,

Accepter le code m'a l'air d'un bug. Mais ce qui m'etonne c'est la
regression dans gcc (pas fixe, fixe, pas fixe). Pour info,


Quand je dis gcc 3.5, il s'agit en fait en fait du compilateur 3.5 beta
fourni avec Fedora Core 3 test 1 :
        gcc version 3.5.0 20040703 (Red Hat Linux 3.5.0-0.3)
Il n'est pas forcément à jour, d'autant plus qu'il semble avoir été retiré
de Fedora Core 3 test 2. Je ne mettrais donc pas ma main à couper qu'il
s'agit d'une régression.


"ComeauTest.c", line 6: error: the initial explicit specialization of
function
"nmr::helper<T>() [with T=char]" must be declared in the
namespace containing the template
template <> void nmr::helper<char>() {
^

1 error detected in the compilation of "ComeauTest.c".


Le message d'erreur semble clair. J'imagine donc qu'il s'agit d'une de ces
obscures subtilités du langage C++ qui sont peu à peu implementées dans les
compilateurs.

Quelqu'un connait-il le paragraphe correspondant de la norme ?

Au passage, dommage que GCC ne prenne pas le problème de la compatibilité
plus au sérieux. Ce changement casse une fois de plus beaucoup de code
existant, il aurait fallu ajouter une option pour éliminer cette erreur.

--
Cyril

Avatar
Falk Tannhäuser
Cyril Poupon wrote:
Le message d'erreur semble clair. J'imagine donc qu'il s'agit d'une de ces
obscures subtilités du langage C++ qui sont peu à peu implementée s dans les
compilateurs.

Quelqu'un connait-il le paragraphe correspondant de la norme ?
§ 14.7.3/2 : "An explicit specialization shall be declared in the names pace

of which the template is a member..."

§ 7.3.1.2/2 : "Members of a named namespace can also be defined outside
that namespace by explicit qualification (3.4.3.2) of the name
being defined, provided that the entity being defined was already
declared in the namespace and the definition appears after the
point of declaration in a namespace that encloses the
declaration's namespace."
ne s'applique donc pas dans le cas d'une spécialisation explicite,
il faut écrire

namespace nmr
{
template<typename T> void helper();
}

// ...

namespace nmr
{
template<> void helper<char>()
{
std::cout << "Bn";
}
}

Falk

Avatar
Jean-Marc Bourguet
Falk Tannhäuser writes:

Cyril Poupon wrote:
Le message d'erreur semble clair. J'imagine donc qu'il s'agit d'une de ces
obscures subtilités du langage C++ qui sont peu à peu implementées dans les
compilateurs.
Quelqu'un connait-il le paragraphe correspondant de la norme ?
§ 14.7.3/2 : "An explicit specialization shall be declared in the namespace

of which the template is a member..."

§ 7.3.1.2/2 : "Members of a named namespace can also be defined outside
that namespace by explicit qualification (3.4.3.2) of the name
being defined, provided that the entity being defined was already
declared in the namespace and the definition appears after the
point of declaration in a namespace that encloses the
declaration's namespace."
ne s'applique donc pas dans le cas d'une spécialisation explicite,
il faut écrire


Je ne comprends pas le "donc" (avec ce que tu as cite, j'ai pas ete
voir le texte complet).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
kanze
Cyril Poupon wrote in message
news:<41628efc$0$26244$...

Au passage, dommage que GCC ne prenne pas le problème de la
compatibilité plus au sérieux. Ce changement casse une fois de plus
beaucoup de code existant, il aurait fallu ajouter une option pour
éliminer cette erreur.


Je suis bien d'accord avec toi, et je m'en suis plaint à plus d'une
occasion. Mais dans ce cas-ci, à leur décharge, c'est extrèmement
difficile à se rendre compte de ce qu'on peut casser avec de tels
changements. Quand il ne s'agit que de changer un test quelque part,
pour interdire quelque chose que tu permettais avant, c'est assez facile
à reconnaître le changement, et à y ajouter une option. Quand tu réécris
toute la logique d'instantiation, en revanche, parce que la contexte
d'instantiation a changé (recherche de noms à deux phases, etc.), c'est
quasi impossible à se rendre compte de tous les détails qui ont changé.
Et ce n'est pas forcement très commode à maintenir deux versions
distinctes de l'instantiation non plus ; je n'y ai pas régardé, mais
j'imagine que c'est plus qu'un peu de code.

Alors, je leur donnerais la bénéfice de la doute ; peut-être s'ils s'en
étaient rendus compte, ou s'ils l'auraient raisonablement pû, ils
auraient prévu une option de compatibilité.

--
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
Jean-Marc Bourguet
Cyril Poupon writes:

Au passage, dommage que GCC ne prenne pas le problème de la compatibilité
plus au sérieux. Ce changement casse une fois de plus beaucoup de code
existant, il aurait fallu ajouter une option pour éliminer cette erreur.


Que 3.4 introduit de gros problemes de compatibilite avec du code
incorrect mais accepte, c'est sur, il a un nouvel analyseur gramatical
totalement reecrit. Voir les deux premiers points des release notes:

http://gcc.gnu.org/gcc-3.4/changes.html#cplusplus

Dans de telles conditions, c'est difficile de leur jeter la pierre.

C'est plus bizarre que ca reapparaisse en 3.5 (qui sera 4.0 si j'ai
bien suivit car la c'est une bonne partie de l'optimisation
independante du langage et de la cible qui est reecrite).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Falk Tannhäuser
Jean-Marc Bourguet wrote:
Falk Tannhäuser writes:

§ 14.7.3/2 : "An explicit specialization shall be declared in the nam espace
of which the template is a member..."

§ 7.3.1.2/2 : "Members of a named namespace can also be defined outsi de
that namespace by explicit qualification (3.4.3.2) of the name
being defined, provided that the entity being defined was already
declared in the namespace and the definition appears after the
point of declaration in a namespace that encloses the
declaration's namespace."
ne s'applique donc pas dans le cas d'une spécialisation explicite,


Je ne comprends pas le "donc" (avec ce que tu as cite, j'ai pas ete
voir le texte complet).


§ 7.3.1.2/2 parle de la définition des membres d'un namespace nommé ,
il dit que, étant donnée la déclaration
namespace foo { void toto(); }
la définition peut aussi être écrite comme
/*(i) */ void foo::toto() {}
et non seulement comme
/*(ii)*/ namespace foo { void toto() {} }

(À mon avis, il s'agit là d'un hack dans la norme, visant à faire
ressembler les 'namespace' un peu plus aux 'class' / 'struct' ;
ces dernières, contrairement aux 'namespace', ne peuvent pas être
rouverts afin de permettre la définition des membres déclarés mais
pas définis à leur intérieur. Personnellement, je préfère la sy ntaxe
(ii) pour définir les membres des 'namespace' - cela permet d'être
plus cohérent avec le cas des 'namespace' anonymes.)

Or, la spécialisation d'un template n'est pas la définition d'un
membre déclaré dans un namespace, c'est pour ça que je disais que
§ 7.3.1.2/2 ne s'y applique pas.

Falk


Avatar
Jean-Marc Bourguet
Falk Tannhäuser writes:

Or, la spécialisation d'un template n'est pas la définition d'un
membre déclaré dans un namespace, c'est pour ça que je disais que §
7.3.1.2/2 ne s'y applique pas.


Je te suggere de lire 14.7.3/2 jusqu'au bout.

[...] If the declaration is not a definition, the specialization may
be defined later in the namespace in which the explicit specialization
was declared, or in a namespace that encloses the one in which the
explicit specialization was declared.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Gabriel Dos Reis
Cyril Poupon writes:

| Au passage, dommage que GCC ne prenne pas le problème de la compatibilité
| plus au sérieux. Ce changement casse une fois de plus beaucoup de code
| existant, il aurait fallu ajouter une option pour éliminer cette erreur.

Nous attendons impatiemment ton patch pour accepter du code invalide,
que nous acceptions par erreur avant (et que nous reconnaissions comme
erreur).

-- Gaby
Avatar
Falk Tannhäuser
Jean-Marc Bourguet wrote:

Je te suggere de lire 14.7.3/2 jusqu'au bout.


Pendant que nous y sommes, lisons-en aussi la partie du milieu :-)
Voici ce paragraphe dans son intégralité :
"An explicit specialization shall be declared in the namespace of
which the template is a member, or, for member templates, in the
namespace of which the enclosing class or enclosing class template
is a member. An explicit specialization of a member function, member
class or static data member of a class template shall be declared in
the namespace of which the class template is a member. Such a
declaration may also be a definition. If the declaration is not a
definition, the specialization may be defined later in the namespace
in which the explicit specialization was declared, or in a namespace
that encloses the one in which the explicit specialization was
declared."

Dans ma compréhension, la dernière phrase s'applique uniquement
à la *définition* des fonctions membre, classes membre ou données
membre statiques des template de classe spécialisés dans le
namespace. Exemple :
__________________________________________________________________
#include <iostream>
#include <ostream>

namespace foo
{
template<int N> struct bar {};

template<> struct bar<42> { void toto(); };
// Spécialisation explicite de 'bar', déclaration sans définition
// de la fonction membre 'toto'
}

#ifdef DEFINITION_IN_NAMESPACE //////////////////////////////////

namespace foo
{
void bar<42>::toto() { std::cout << "Hello world!n"; }
// Définition de cette fonction membre à l'intérieur du namespace
}

#else ///////////////////////////////////////////////////////////

void foo::bar<42>::toto() { std::cout << "Hello world!n"; }
// Définition dans le namespace englobant, conformément à la
// dernière phrase du § 14.7.3/2

#endif //////////////////////////////////////////////////////////

int main()
{
foo::bar<42> b;
b.toto();
return 0;
}
__________________________________________________________________

AMA, ce que dit § 14.7.3/2, c'est que les 2 variantes de définir
'foo::bar<42>::toto()' sont légales. En revanche, la spécialisation
explicite de la classe 'bar' ne pourrait pas apparaître au niveau
du namespace global, comme
template<> struct foo::bar<42> { void toto(); };

Falk

1 2