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.
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.
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érer Hello::World
et où considérer World
. 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.
}
}
using namespace Hello;
intérieur des autres namespace
également (et en déclarant la extern
fonction à l'intérieur).
Hello::World Blah::DoSomething()
ou Blah::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 la using
par une typedef 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]:
using-directive : using namespace :: opt imbriqué-name-spécificateur opt namespace-name ;
Une directive using 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. [Note: lors de la recherche d'un nom d'espace de noms dans une directive using, seuls les noms d'espace de noms sont pris en compte, voir 3.4.6. ]
Pourquoi le standard C ++ l'interdit? Je ne sais pas, demandez à un membre du comité ISO qui a approuvé la norme linguistique.
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 la using
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.
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 utilise using
.
using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bind
namespace 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.
}
namespace Foo
à l'ordre de recherche pour tout le code à l'intérieur de la définition de type de struct 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
{
}
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.