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.
c++
namespaces
using
language-lawyer
iammilind
la source
la source
using namespace
. C # permet quelque chose de similaire, mais à la portée du fichier uniquement. C ++using namespace
vous permet d'incorporer un espace de noms dans un autre.class/struct
. Ce n'est tout simplement pas autorisé. Mais la réponse acceptée discute une justification très logique pour la rejeter. c'est-à-dire où considérerHello::World
et où considérerWorld
. J'espère que cela dissipe le doute.Réponses:
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? }
Comme il n'y a pas de 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 d'étendues 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. } }
la source
using namespace Hello;
intérieur des autresnamespace
également (et en déclarant laextern
fonction à l'intérieur).Hello::World Blah::DoSomething()
ouBlah::World Blah::DoSomething()
(si cela était autorisé), le type de retour d'une définition de fonction membre n'est pas considéré comme faisant partie de la portée de la classe dans le langage, il doit donc être qualifié. Prenons l'exemple valide de remplacement de lausing
par unetypedef Hello::World World;
portée de classe at. Il ne devrait donc y avoir aucune surprise.Parce que le standard C ++ l'interdit explicitement. De C ++ 03 §7.3.4 [namespace.udir]:
Pourquoi le standard C ++ l'interdit? Je ne sais pas, demandez à un membre du comité ISO qui a approuvé la norme linguistique.
la source
Je pense que le raisonnement est que ce serait probablement déroutant. Actuellement, lors du traitement d'un identificateur de niveau de classe, la recherche recherche d'abord dans la portée de la classe, puis dans l'espace de noms englobant. Autoriser le
using namespace
niveau de la classe aurait des 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 au niveau de l'espace de noms utilisé, 2) rechercher l'espace de noms utilisé après la portée de classe mais avant toute autre portée de classe, 3) rechercher 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
déclaration au niveau de l'espace de noms. Cela n'ajouterait aucune nouvelle valeur à cela, mais compliquerait en revanche la recherche des implémenteurs de compilateurs. La recherche d'identifiant d'espace de noms est désormais indépendante de l'endroit où la recherche est déclenchée dans le code. À l'intérieur d'une classe, si la recherche ne trouve pas l'identificateur dans la portée de la classe, elle 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 lausing
déclaration est trouvée au niveau de l'espace de noms, le contenu de l' espace de noms utilisé est introduit dans cet espace de noms pour toutes les recherches impliquant l'espace de noms. Siusing 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 exactement selon l'endroit d'où la recherche a été déclenchée, et cela rendrait l'implémentation de la recherche beaucoup plus complexe sans valeur supplémentaire.Quoi qu'il en soit, ma recommandation est de ne pas utiliser du
using namespace
tout la déclaration. Cela rend le code plus simple à raisonner sans avoir à garder à l'esprit le contenu de tous les espaces de noms.la source
using
existe. En déclarant délibérément des choses dans de longs espaces de noms imbriqués. Par exemple,glm
fait cela et utilise plusieurs astuces pour activer / présenter des fonctionnalités lorsque le client utiliseusing
.using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bindnamespace ph = std::placeholders;
Ceci est probablement interdit en raison de l' ouverture par rapport à la fermeture.
L'importation d'espaces de noms dans des classes conduirait à des cas amusants comme celui-ci:
namespace Foo {} struct Bar { using namespace Foo; }; namespace Foo { using Baz = int; // I've just extended `Bar` with a type alias! void baz(); // I've just extended `Bar` with what looks like a static function! // etc. }
la source
namespace Foo
à l'ordre de recherche pour tout le code à l'intérieur de la définition de type destruct Bar
, un peu comme mettre cette ligne dans chaque corps de fonction membre en ligne, sauf qu'elle serait également active pour les initialiseurs d'accolade ou d'égalité, etc. expire à l'accolade fermante, comme à l'using namespace
intérieur d'un corps de fonction membre. Maintenant, il ne semble malheureusement pas y avoir de moyen d'utiliser la recherche Koenig-with-fallback dans un initialiseur d'accolade ou d'égalité sans polluer l'espace de noms englobant.Je pense que c'est un défaut de langage. Vous pouvez utiliser la solution de contournement ci-dessous. En gardant à l'esprit cette solution de contournement, il est facile de suggérer des règles de résolution des conflits de noms pour le cas où la langue sera modifiée.
namespace Hello { typedef int World; } // surround the class (where we want to use namespace Hello) // by auxiliary namespace (but don't use anonymous namespaces in h-files) namespace Blah_namesp { using namespace Hello; class Blah { public: World DoSomething1(); World DoSomething2(); World DoSomething3(); }; World Blah::DoSomething1() { } } // namespace Blah_namesp // "extract" class from auxiliary namespace using Blah_namesp::Blah; Hello::World Blah::DoSomething2() { } auto Blah::DoSomething3() -> World { }
la source