class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Modifica : vuoi conoscere la motivazione dietro di esso.
class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Modifica : vuoi conoscere la motivazione dietro di esso.
class/struct
. Semplicemente non è permesso. Ma la risposta accettata discute una logica molto logica per rifiutarla. vale a dire dove considerare Hello::World
e dove considerare World
. Spero che cancelli il dubbio.
Risposte:
Non lo so esattamente, ma la mia ipotesi è che consentire questo nell'ambito della classe potrebbe causare confusione:
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?
}
Poiché non esiste un modo ovvio per farlo, lo standard dice semplicemente che non puoi.
Ora, il motivo per cui questo crea meno confusione quando parliamo di ambiti dello spazio dei nomi:
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;
all'interno di altri namespace
(e dichiarando la extern
funzione al suo interno).
Hello::World Blah::DoSomething()
o Blah::World Blah::DoSomething()
(se consentito), il tipo restituito di una definizione di funzione membro non è considerato nell'ambito della classe nella lingua, quindi deve essere qualificato. Considera il valido esempio di sostituzione di using
con un typedef Hello::World World;
ambito di classe. Quindi non dovrebbero esserci sorprese lì.
Perché lo standard C ++ lo proibisce esplicitamente. Da C ++ 03 §7.3.4 [namespace.udir]:
using-Directive : using namespace :: opt specificatore-nome-annidato opt namespace-name ;
Una direttiva using non deve apparire nell'ambito della classe, ma può apparire nell'ambito dello spazio dei nomi o nell'ambito del blocco. [Nota: quando si cerca un nome-spazio dei nomi in una direttiva using, vengono considerati solo i nomi degli spazi dei nomi, vedere 3.4.6. ]
Perché lo standard C ++ lo vieta? Non lo so, chiedi a un membro del comitato ISO che ha approvato lo standard linguistico.
Credo che la logica sia che probabilmente creerebbe confusione. Attualmente, durante l'elaborazione di un identificatore a livello di classe, la ricerca cercherà prima nell'ambito della classe e poi nello spazio dei nomi che lo racchiude. Consentire il using namespace
livello di classe avrebbe alcuni effetti collaterali sul modo in cui viene eseguita la ricerca. In particolare, dovrebbe essere eseguito a volte tra il controllo di quel particolare ambito di classe e il controllo dello spazio dei nomi che lo racchiude. Ovvero: 1) unire le ricerche a livello di classe e quelle a livello di spazio dei nomi utilizzato, 2) cercare lo spazio dei nomi utilizzato dopo l'ambito della classe ma prima di qualsiasi altro ambito di classe, 3) cercare lo spazio dei nomi utilizzato subito prima dello spazio dei nomi che lo racchiude. 4) ricerca fusa con lo spazio dei nomi che lo racchiude.
.
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
dichiarazione a livello di spazio dei nomi. Non aggiungerebbe alcun nuovo valore a ciò, ma d'altro canto complicherà la ricerca per gli implementatori del compilatore. La ricerca dell'identificatore dello spazio dei nomi è ora indipendente da dove viene attivata la ricerca nel codice. Quando si è all'interno di una classe, se la ricerca non trova l'identificatore nell'ambito della classe, tornerà alla ricerca nello spazio dei nomi, ma questa è esattamente la stessa ricerca nello spazio dei nomi utilizzata nella definizione di una funzione, non è necessario mantenere il nuovo stato. Quando la using
dichiarazione si trova a livello di spazio dei nomi, il contenuto dello spazio dei nomi utilizzato viene portato in quello spazio dei nomi per tutti ricerche che coinvolgono lo spazio dei nomi. Seusing namespace
era consentito a livello di classe, ci sarebbero risultati diversi per la ricerca nello spazio dei nomi dello stesso identico spazio dei nomi a seconda di dove è stata attivata la ricerca, e ciò renderebbe l'implementazione della ricerca molto più complessa senza alcun valore aggiuntivo.Ad ogni modo, la mia raccomandazione è di non utilizzare affatto la using namespace
dichiarazione. Rende il codice più semplice da ragionare senza dover tenere a mente tutti i contenuti degli spazi dei nomi.
using
esiste. Dichiarando intenzionalmente le cose in spazi dei nomi lunghi e annidati. Ad esempio, lo glm
fa e utilizza più trucchi per attivare / presentare le funzionalità quando il client lo utilizza using
.
using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bind
namespace ph = std::placeholders;
Questo probabilmente non è consentito a causa dell'apertura e della chiusura.
L'importazione di spazi dei nomi nelle classi porterebbe a casi divertenti come questo:
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
all'ordine di ricerca per tutto il codice all'interno della definizione del tipo di struct Bar
, proprio come inserire quella riga in ogni corpo della funzione membro inline, tranne per il fatto che sarebbe attivo anche per gli inizializzatori parentesi graffe o uguali, ecc. scadono alla parentesi graffa di chiusura, come using namespace
all'interno del corpo della funzione di un membro. Ora sfortunatamente non sembra esserci alcun modo per utilizzare Koenig-with-fallback lookup in un inizializzatore di parentesi graffe o uguali senza inquinare lo spazio dei nomi che lo racchiude.
Penso che sia un difetto della lingua. È possibile utilizzare la soluzione alternativa di seguito. Tenendo presente questa soluzione alternativa, è facile suggerire regole per la risoluzione dei conflitti di nomi per il caso in cui la lingua verrà modificata.
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 # consente qualcosa di simile, ma solo nell'ambito del file. Il C ++using namespace
ti permette di incorporare uno spazio dei nomi in un altro.