class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Bearbeiten : Willst du die Motivation dahinter wissen.
class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Bearbeiten : Willst du die Motivation dahinter wissen.
class/struct
. Es ist einfach nicht erlaubt. Die akzeptierte Antwort diskutiert jedoch eine sehr logische Begründung, um sie nicht zuzulassen. dh wo zu berücksichtigen Hello::World
und wo zu berücksichtigen World
. Hoffe das klärt den Zweifel.
Antworten:
Ich weiß es nicht genau, aber ich vermute, dass das Zulassen im Klassenbereich Verwirrung stiften kann:
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?
}
Da es keinen offensichtlichen Weg gibt, dies zu tun, sagt der Standard nur, dass Sie nicht können.
Der Grund dafür ist weniger verwirrend, wenn es um Namespace-Bereiche geht:
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;
Innere des Anderen namespace
(und das Deklarieren der extern
Funktion darin).
Hello::World Blah::DoSomething()
oder Blah::World Blah::DoSomething()
(wenn es erlaubt war), der Rückgabetyp einer Elementfunktionsdefinition wird nicht als im Umfang der Klasse in der Sprache liegend angesehen, daher muss er qualifiziert werden. Betrachten Sie das gültige Beispiel für das Ersetzen von using
durch einen typedef Hello::World World;
at-Klassenbereich. Es sollte also keine Überraschungen geben.
Weil der C ++ - Standard dies ausdrücklich verbietet. Ab C ++ 03 §7.3.4 [namespace.udir]:
using-Direktive : using namespace :: opt verschachtelter name-spezifizierer opt namespace-name ;
Eine using-Direktive darf nicht im Klassenbereich erscheinen, sondern kann im Namespace-Bereich oder im Blockbereich erscheinen. [Hinweis: Beim Nachschlagen eines Namespace-Namens in einer using-Direktive werden nur Namespace-Namen berücksichtigt, siehe 3.4.6. ]]
Warum verbietet der C ++ - Standard dies? Ich weiß nicht, fragen Sie ein Mitglied des ISO-Komitees, das den Sprachstandard genehmigt hat.
Ich glaube, das Grundprinzip ist, dass es wahrscheinlich verwirrend wäre. Derzeit wird bei der Verarbeitung einer Kennung auf Klassenebene die Suche zuerst im Klassenbereich und dann im umschließenden Namespace gesucht. Das Zulassen using namespace
auf Klassenebene hätte einige Nebenwirkungen auf die Art und Weise, wie die Suche jetzt durchgeführt wird. Insbesondere müsste es irgendwann zwischen der Überprüfung dieses bestimmten Klassenbereichs und der Überprüfung des umschließenden Namespace durchgeführt werden. Das heißt: 1) Zusammenführen der Suchvorgänge auf Klassenebene und verwendeter Namespace-Ebene, 2) Nachschlagen des verwendeten Namespace nach dem Klassenbereich, jedoch vor jedem anderen Klassenbereich, 3) Nachschlagen des verwendeten Namespace direkt vor dem umschließenden Namespace. 4) Suche mit dem umschließenden Namespace zusammengeführt.
.
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
Deklaration auf Namespace-Ebene. Dies würde keinen neuen Wert hinzufügen, würde jedoch die Suche nach Compiler-Implementierern erschweren. Die Suche nach Namespace-IDs ist jetzt unabhängig davon, wo im Code die Suche ausgelöst wird. Wenn in einer Klasse die Suche den Bezeichner im Klassenbereich nicht findet, wird auf die Namespace-Suche zurückgegriffen. Dies ist jedoch genau die gleiche Namespace-Suche, die in einer Funktionsdefinition verwendet wird. Es ist nicht erforderlich, einen neuen Status beizubehalten. Wenn die using
Erklärung auf Namespace - Ebene gefunden wird, wird der Inhalt des verwendeten sind Namensraum gebracht , in diesem Namensraum für alle Lookups den Namensraum beinhaltet. Wennusing namespace
Wurde auf Klassenebene zugelassen, würde es unterschiedliche Ergebnisse für die Namespace-Suche mit genau demselben Namespace geben, je nachdem, von wo aus die Suche ausgelöst wurde, und dies würde die Implementierung der Suche ohne zusätzlichen Wert viel komplexer machen.Ich empfehle jedenfalls, die Erklärung überhaupt nicht zu verwenden using namespace
. Es macht es einfacher, mit Code zu argumentieren, ohne den Inhalt aller Namespaces berücksichtigen zu müssen.
using
. Indem wir Dinge absichtlich in tief verschachtelten langen Namespaces deklarieren. ZB glm
tut dies und verwendet mehrere Tricks, um Funktionen zu aktivieren / präsentieren, wenn der Client sie verwendet using
.
using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bind
namespace ph = std::placeholders;
Dies ist wahrscheinlich wegen Offenheit gegen Geschlossenheit nicht erlaubt.
Das Importieren von Namespaces in Klassen würde zu lustigen Fällen wie diesen führen:
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.
}
Ich denke, es ist ein Sprachfehler. Sie können die unten stehende Problemumgehung verwenden. Unter Berücksichtigung dieser Problemumgehung ist es einfach, Regeln für die Lösung von Namenskonflikten für den Fall vorzuschlagen, dass die Sprache geändert wird.
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 # erlaubt etwas Ähnliches, jedoch nur im Dateibereich. Mit C ++using namespace
können Sie einen Namespace in einen anderen integrieren.