Les membres de la classe peuvent-ils être définis en dehors de l’espace de noms dans lequel ils sont déclarés?

Parfois, je trouve un code comme celui-ci (en fait, certains assistants de classe créent ce code):

// Ch namespace NS { class C { void f(); }; } 

et dans le fichier d’implémentation:

 // C.cpp #include "Ch" using namespace NS; void C::f() { //... } 

Tous les compilateurs que j’ai essayés acceptent ce genre de code (gcc, clang, msvc, comstackonline.com). Ce qui me rend mal à l’aise, c’est l’ using namespace NS; . De mon sharepoint vue, C::f() réside dans l’espace de noms global dans un environnement disposant d’un access non qualifié aux objects situés dans l’espace de noms NS. Mais selon le compilateur, le void C::f() habite dans l’ namespace NS de namespace NS . Comme tous les compilateurs que j’ai essayés partagent ce sharepoint vue, ils ont probablement raison, mais dans quelle norme cette opinion est-elle soutenue?

Oui, la syntaxe est certes légale , mais non, votre fonction vit dans l’espace de noms NS . Le code que vous voyez est en fait équivalent à

 namespace NS { void C::f() { /* ... } } 

ou pour

 void NS::C::f() { /* ... */ } 

ce qui peut être plus semblable à ce que vous êtes habitué.

En raison de la directive using, vous pouvez omettre la partie NS non seulement dans le code appelant, mais également dans sa définition. La norme a un exemple qui correspond à votre code (après la partie soulignée en gras):

3.4.3.2 Membres d’espace de noms [namespace.qual]

7 Dans une déclaration d’un membre d’espace de nom dans laquelle l’identificateur de déclarant est un identificateur qualifié, étant donné que l’identificateur qualifié du membre d’espace de nom prend la forme spécificateur de nom nested, identificateur non qualifié, l’identificateur non qualifié doit l’espace de nom désigné par le spécificateur de nom nested ou d’un élément de l’ensemble d’espaces de noms intégré (7.3.1) de cet espace de noms. [ Exemple:

 namespace A { namespace B { void f1(int); } using namespace B; } void A::f1(int){ } // ill-formed, f1 is not a member of A 

—End example] Cependant, dans de telles déclarations de membres d’espaces de noms, le spécificateur de nom nested peut s’appuyer sur des directives using pour fournir implicitement la partie initiale du spécificateur de nom nested. [ Exemple:

 namespace A { namespace B { void f1(int); } } namespace C { namespace D { void f1(int); } } using namespace A; using namespace C::D; void B::f1(int){ } // OK, defines A::B::f1(int) 

—Fin exemple]

Vous pouvez donc omettre la partie initiale du spécificateur de nom nested, mais aucune partie intermédiaire .