class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Edit: Vous voulez connaître la motivation derrière cela.
Je ne sais pas exactement, mais je suppose que permettre cela à la portée de la classe pourrait causer de la confusion:
namespace Hello
{
typedef int World;
}
class Blah
{
using namespace Hello;
public:
World DoSomething();
}
//Should this be just World or Hello::World ?
World Blah::DoSomething()
{
//Is the using namespace valid in here?
}
Puisqu'il n'y a aucun moyen évident de le faire, la norme dit simplement que vous ne pouvez pas.
Maintenant, la raison pour laquelle cela est moins déroutant lorsque nous parlons de portées d'espace de noms:
namespace Hello
{
typedef int World;
}
namespace Other
{
using namespace Hello;
World DoSomething();
}
//We are outside of any namespace, so we have to fully qualify everything. Therefore either of these are correct:
//Hello was imported into Other, so everything that was in Hello is also in Other. Therefore this is okay:
Other::World Other::DoSomething()
{
//We're outside of a namespace; obviously the using namespace doesn't apply here.
//EDIT: Apparently I was wrong about that... see comments.
}
//The original type was Hello::World, so this is okay too.
Hello::World Other::DoSomething()
{
//Ditto
}
namespace Other
{
//namespace Hello has been imported into Other, and we are inside Other, so therefore we never need to qualify anything from Hello.
//Therefore this is unambiguiously right
World DoSomething()
{
//We're inside the namespace, obviously the using namespace does apply here.
}
}
Parce que la norme C++ l'interdit explicitement. Depuis C++ 03 §7.3.4 [namespace.udir]:
directive d'utilisation: en utilisant l'espace de noms ::optspécificateur de nom imbriquéoptnamespace-name ;
A sing-directive ne doit pas apparaître dans la portée de la classe, mais peut apparaître dans la portée de l'espace de noms ou dans la portée du bloc. [Remarque: lors de la recherche d'un nom d'espace de noms dans une directive using, seuls les noms d'espaces de noms sont pris en compte, voir 3.4.6. ]
Pourquoi la norme C++ l'interdit-elle? Je ne sais pas, demandez à un membre du comité ISO qui a approuvé la norme linguistique.
Je pense que la justification est que ce serait probablement déroutant. Actuellement, lors du traitement d'un identifiant de niveau de classe, la recherche cherchera d'abord dans la portée de la classe, puis dans l'espace de noms englobant. Autoriser le using namespace
au niveau de la classe aurait quelques effets secondaires sur la façon dont la recherche est maintenant effectuée. En particulier, il devrait être effectué entre la vérification de cette portée de classe particulière et la vérification de l'espace de noms englobant. C'est-à-dire: 1) fusionner le niveau de classe et les recherches de niveau d'espace de nom utilisées, 2) rechercher l'espace de nom utilisé après l'étendue de classe mais avant toute autre étendue de classe, 3) recherchez l'espace de noms utilisé juste avant l'espace de noms englobant. 4) recherche fusionnée avec l'espace de noms englobant.
.
namespace A {
void foo() {}
struct B {
struct foo {};
void f() {
foo(); // value initialize a A::B::foo object (current behavior)
}
};
}
struct C {
using namespace A;
struct foo {};
void f() {
foo(); // call A::foo
}
};
.
namespace A {
void foo() {}
}
void bar() {}
struct base {
void foo();
void bar();
};
struct test : base {
using namespace A;
void f() {
foo(); // A::foo()
bar(); // base::bar()
}
};
.
namespace A {
void foo( int ) { std::cout << "int"; }
}
void foo( double ) { std::cout << "double"; }
struct test {
using namespace A;
void f() {
foo( 5.0 ); // would print "int" if A is checked *before* the
// enclosing namespace
}
};
using
au niveau de l'espace de noms. Cela n'ajouterait aucune nouvelle valeur à cela, mais compliquerait en revanche la recherche d'implémenteurs de compilateur. La recherche d'identifiant d'espace de noms est désormais indépendante de l'endroit où dans le code la recherche est déclenchée. À l'intérieur d'une classe, si la recherche ne trouve pas l'identifiant à la portée de la classe, il reviendra à la recherche d'espace de noms, mais c'est exactement la même recherche d'espace de noms que celle utilisée dans une définition de fonction, il n'est pas nécessaire de maintenir un nouvel état. Lorsque la déclaration using
est trouvée au niveau de l'espace de noms, le contenu de l'espace de noms utilisé est amené dans cet espace de noms pour toutes les recherches impliquant l'espace de noms. Si using namespace
était autorisé au niveau de la classe, il y aurait des résultats différents pour la recherche d'espace de noms du même espace de noms selon l'endroit d'où la recherche a été déclenchée, ce qui rendrait l'implémentation de la recherche beaucoup plus complexe sans valeur supplémentaire.Quoi qu'il en soit, ma recommandation est pas d'employer le using namespace
déclaration du tout. Il rend le code plus simple à raisonner sans avoir à garder à l'esprit le contenu de tous les espaces de noms.