Namespaces
Variants

Namespaces

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Namespace declaration
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Namespaces bieten eine Methode zur Vermeidung von Namenskonflikten in großen Projekten.

In einem Namespace-Block deklarierte Entitäten werden in einen Namespace-Bereich platziert, was verhindert, dass sie mit gleichnamigen Entitäten in anderen Bereichen verwechselt werden.

Außerhalb aller Namespace-Blöcke deklarierte Entitäten gehören zum globalen Namespace . Der globale Namespace gehört zum globalen Scope und kann explizit mit einem vorangestellten :: referenziert werden. Obwohl er keine Deklaration besitzt, ist der globale Namespace kein unbenannter Namespace .

Mehrere Namespace-Blöcke mit demselben Namen sind erlaubt. Alle Deklarationen innerhalb dieser Blöcke werden im selben Namespace-Bereich deklariert.

Inhaltsverzeichnis

Syntax

namespace ns-name { Deklarationen } (1)
inline namespace ns-name { Deklarationen } (2) (seit C++11)
namespace { Deklarationen } (3)
ns-name :: member-name (4)
using namespace ns-name ; (5)
using ns-name :: member-name ; (6)
namespace name = qualified-namespace ; (7)
namespace ns-name :: member-name { Deklarationen } (8) (seit C++17)
namespace ns-name :: inline member-name { Deklarationen } (9) (seit C++20)
1) Benannte Namespace-Definition für den Namespace ns-name .
2) Inline-Namespace-Definition für den Namespace ns-name . Deklarationen innerhalb von ns-name werden in seinem umschließenden Namespace sichtbar sein.
3) Unbenannte Namespace-Definition . Deren Mitglieder haben einen potenziellen Gültigkeitsbereich von ihrem Deklarationspunkt bis zum Ende der Übersetzungseinheit und besitzen interne Verknüpfung .
4) Namespace-Namen (zusammen mit Klassennamen) können auf der linken Seite des Bereichsauflösungsoperators erscheinen, als Teil der qualifizierten Namenssuche .
5) using-Direktive : Aus Sicht der unqualifizierten Namenssuche für jeden Namen nach einer using-Direktive und bis zum Ende des Gültigkeitsbereichs, in dem sie erscheint, ist jeder Name aus ns-name sichtbar, als wäre er im nächstgelegenen einschließenden Namespace deklariert, der sowohl die using-Direktive als auch ns-name enthält.
6) using-declaration : macht das Symbol member-name aus dem Namespace ns-name zugänglich für unqualified lookup , als wäre es im selben Klassenbereich, Blockbereich oder Namespace deklariert, in dem diese using-declaration erscheint.
namespace-alias-definition : macht name zu einem Synonym für einen anderen Namespace: siehe namespace alias
8) Verschachtelte Namespace-Definition: namespace A :: B :: C { ... } ist äquivalent zu namespace A { namespace B { namespace C { ... } } } .
9) Verschachtelte Inline-Namespace-Definition: namespace A :: B :: inline C { ... } ist äquivalent zu namespace A :: B { inline namespace C { ... } } . inline kann vor jedem Namespace-Namen außer dem ersten erscheinen: namespace A :: inline B :: C { } ist äquivalent zu namespace A { inline namespace B { namespace C { } } } .

Erklärung

Namespaces

inline (optional) namespace attr  (optional) identifier { namespace-body }
inline - (seit C++11) falls vorhanden, macht dies zu einem Inline-Namespace (siehe unten). Darf nicht in der extension-namespace-definition erscheinen, wenn die original-namespace-definition nicht inline verwendete
attr - (seit C++17) optionale Folge beliebig vieler Attribute
identifier - entweder
  • ein bisher unverwendeter Bezeichner, in diesem Fall ist dies eine original-namespace-definition ;
  • der Name eines Namespace, in diesem Fall ist dies eine extension-namespace-definition ;
  • eine Folge von umschließenden Namespace-Spezifizierern, getrennt durch :: , endend mit identifier , in diesem Fall ist dies eine nested-namespace-definition
(seit C++17)
namespace-body - möglicherweise leere Folge von Deklarationen beliebiger Art (einschließlich Klassen- und Funktionsdefinitionen sowie verschachtelter Namespaces)

Namespacedefinitionen sind nur auf Namespace-Ebene zulässig, einschließlich des globalen Gültigkeitsbereichs.

Um einen bestehenden Namespace wieder zu öffnen (formal, um eine extension-namespace-definition zu sein), muss die Suche nach dem identifier , der in der Namespace-Definition verwendet wird, zu einem Namespace-Namen (keinem Namespace-Alias) aufgelöst werden, der als Mitglied des umschließenden Namespace oder eines inline-Namespace innerhalb eines umschließenden Namespace deklariert wurde.

Der namespace-body definiert einen namespace scope , welcher sich auf name lookup auswirkt.

Alle Namen, die durch die Deklarationen eingeführt werden, die innerhalb des namespace-body erscheinen (einschließlich verschachtelter Namespace-Definitionen), werden zu Mitgliedern des Namespace identifier , unabhängig davon, ob es sich bei dieser Namespace-Definition um die ursprüngliche Namespace-Definition handelt (die den identifier eingeführt hat) oder um eine erweiternde Namespace-Definition (die den bereits definierten Namespace "wieder geöffnet" hat).

Ein Namespace-Mitglied, das innerhalb eines Namespace-Körpers deklariert wurde, kann außerhalb davon unter Verwendung expliziter Qualifikation definiert oder erneut deklariert werden

namespace Q
{
    namespace V   // V ist ein Mitglied von Q und ist vollständig innerhalb von Q definiert
    { // namespace Q::V { // C++17 Alternative zu den obigen Zeilen
        class C { void m(); }; // C ist ein Mitglied von V und ist vollständig innerhalb von V definiert
                               // C::m ist nur deklariert
        void f(); // f ist ein Mitglied von V, aber hier nur deklariert
    }
    void V::f() // Definition des Mitglieds f von V außerhalb von V
                // Die einschließenden Namensräume von f sind weiterhin der globale Namensraum, Q und Q::V
    {
        extern void h(); // Dies deklariert ::Q::V::h
    }
    void V::C::m() // Definition von V::C::m außerhalb des Namensraums (und des Klassenkörpers)
                   // Einschließende Namensräume sind der globale Namensraum, Q und Q::V
    {}
}

Definitionen und Neudeklarationen außerhalb des Namespace sind nur erlaubt

  • nach dem Punkt der Deklaration,
  • im Namensbereichs-Scope, und
  • in Namensbereichen, die den ursprünglichen Namensbereich umschließen (einschließlich des globalen Namensbereichs).

Außerdem müssen sie die qualified-id-Syntax verwenden.

namespace Q
{
    namespace V    // ursprüngliche Namensraumdefinition für V
    {
        void f();  // Deklaration von Q::V::f
    }
    void V::f() {} // OK
    void V::g() {} // Fehler: g() ist noch kein Mitglied von V
    namespace V    // erweiterte Namensraumdefinition für V
    {
        void g();  // Deklaration von Q::V::g
    }
}
namespace R           // kein umschließender Namensraum für Q
{
    void Q::V::g() {} // Fehler: Q::V::g kann nicht innerhalb von R definiert werden
}
void Q::V::g() {}     // OK: globaler Namensraum umschließt Q

Durch friend -Deklarationen in einer nicht-lokalen Klasse X eingeführte Namen werden zu Mitgliedern des innersten umschließenden Namespace von X, sie werden jedoch nicht durch gewöhnliche Namenssuche sichtbar (weder unqualifiziert noch qualifiziert ), es sei denn, eine entsprechende Deklaration wird im Namespace-Bereich bereitgestellt, entweder vor oder nach der Klassendefinition. Solche Namen können durch ADL gefunden werden, die sowohl Namespaces als auch Klassen berücksichtigt.

Nur der innerste umschließende Namespace wird bei einer solchen Friend-Deklaration berücksichtigt, wenn entschieden wird, ob der Name mit einem zuvor deklarierten Namen in Konflikt stehen würde.

void h(int);
namespace A
{
    class X
    {
        friend void f(X);       // A::f ist ein Friend
        class Y
        {
            friend void g();    // A::g ist ein Friend
            friend void h(int); // A::h ist ein Friend, kein Konflikt mit ::h
        };
    };
    // A::f, A::g und A::h sind im Namensbereich nicht sichtbar
    // obwohl sie Mitglieder des Namensbereichs A sind
    X x;
    void g()  // Definition von A::g
    {
        f(x); // A::X::f wird durch ADL gefunden
    }
    void f(X) {}   // Definition von A::f
    void h(int) {} // Definition von A::h
    // A::f, A::g und A::h sind jetzt im Namensbereich sichtbar
    // und sie sind auch Friends von A::X und A::X::Y
}

Inline-Namespaces

Ein Inline-Namespace ist ein Namespace, der das optionale Schlüsselwort inline in seiner original-namespace-definition verwendet.

Member eines Inline-Namespaces werden in vielen Situationen (unten aufgelistet) so behandelt, als wären sie Member des umschließenden Namespaces. Diese Eigenschaft ist transitiv: Wenn ein Namespace N einen Inline-Namespace M enthält, der wiederum einen Inline-Namespace O enthält, dann können die Member von O so verwendet werden, als wären sie Member von M oder N.

  • Eine using-directive , die den Inline-Namespace benennt, wird implizit im umschließenden Namespace eingefügt (ähnlich der impliziten using-directive für den unbenannten Namespace)
  • Beim argument-dependent lookup werden, wenn ein Namespace zur Menge der assoziierten Namespaces hinzugefügt wird, auch seine Inline-Namespaces hinzugefügt, und wenn ein Inline-Namespace zur Liste der assoziierten Namespaces hinzugefügt wird, wird auch sein umschließender Namespace hinzugefügt.
  • Jeder Member eines Inline-Namespaces kann partiell spezialisiert, explizit instanziiert oder explizit spezialisiert werden, als wäre er ein Member des umschließenden Namespaces.
  • Qualifizierte name lookup , die den umschließenden Namespace untersucht, schließt die Namen aus den Inline-Namespaces ein, selbst wenn derselbe Name im umschließenden Namespace vorhanden ist.
// in C++14, std::literals and its member namespaces are inline
{
    using namespace std::string_literals; // makes visible operator""s 
                                          // from std::literals::string_literals
    auto str = "abc"s;
}
{
    using namespace std::literals; // makes visible both
                                   // std::literals::string_literals::operator""s
                                   // and std::literals::chrono_literals::operator""s
    auto str = "abc"s;
    auto min = 60s;
}
{
    using std::operator""s; // makes both std::literals::string_literals::operator""s
                            // and std::literals::chrono_literals::operator""s visible
    auto str = "abc"s;
    auto min = 60s;
}

Hinweis: Die Regel über Spezialisierungen erlaubt Bibliotheksversionierung: Unterschiedliche Implementierungen einer Bibliotheksvorlage können in verschiedenen Inline-Namespaces definiert werden, während der Benutzer weiterhin den übergeordneten Namespace mit einer expliziten Spezialisierung der primären Vorlage erweitern kann:

namespace Lib
{
    inline namespace Lib_1
    {
        template<typename T> class A; 
    }
    template<typename T> void g(T) { /* ... */ }
}
/* ... */
struct MyClass { /* ... */ };
namespace Lib
{
    template<> class A<MyClass> { /* ... */ };
}
int main()
{
    Lib::A<MyClass> a;
    g(a);  // ok, Lib is an associated namespace of A
}
(seit C++11)

Unbenannte Namensräume

Die unnamed-namespace-definition ist eine Namespace-Definition der Form

inline (optional) namespace attr  (optional) { namespace-body }
inline - (since C++11) falls vorhanden, macht dies zu einem Inline-Namespace
attr - (since C++17) optionale Sequenz beliebig vieler Attribute

Diese Definition wird behandelt als eine Definition eines Namensraums mit eindeutigem Namen und einer using-Direktive im aktuellen Gültigkeitsbereich, die diesen unbenannten Namensraum nominiert (Hinweis: implizit hinzugefügte using-Direktive macht den Namensraum verfügbar für die qualifizierte Namenssuche und unqualifizierte Namenssuche , aber nicht für die argumentabhängige Suche ). Der eindeutige Name ist über das gesamte Programm hinweg eindeutig, aber innerhalb einer Übersetzungseinheit ordnet sich jede unbenannte Namensraumdefinition demselben eindeutigen Namen zu: Mehrere unbenannte Namensraumdefinitionen im selben Gültigkeitsbereich bezeichnen denselben unbenannten Namensraum.

namespace
{
    int i; // definiert ::(unique)::i
}
void f()
{
    i++;   // inkrementiert ::(unique)::i
}
namespace A
{
    namespace
    {
        int i;        // A::(unique)::i
        int j;        // A::(unique)::j
    }
    void g() { i++; } // A::(unique)::i++
}
using namespace A; // führt alle Namen aus A in den globalen Namespace ein
void h()
{
    i++;    // Fehler: ::(unique)::i und ::A::(unique)::i sind beide im Scope
    A::i++; // ok, inkrementiert ::A::(unique)::i
    j++;    // ok, inkrementiert ::A::(unique)::j
}

Obwohl Namen in einem unbenannten Namespace mit externer Verknüpfung deklariert werden können, sind sie von anderen Übersetzungseinheiten nie zugänglich, da ihr Namespace-Name eindeutig ist.

(until C++11)

Unbenannte Namespaces sowie alle direkt oder indirekt innerhalb eines unbenannten Namespaces deklarierten Namespaces besitzen interne Verknüpfung , was bedeutet, dass jeder Name, der innerhalb eines unbenannten Namespaces deklariert wird, interne Verknüpfung besitzt.

(since C++11)

Using-Deklarationen

Führt einen Namen, der an anderer Stelle definiert ist, in den deklarativen Bereich ein, in dem diese using-Deklaration erscheint.

using typename (optional) nested-name-specifier unqualified-id ; (bis C++17)
using declarator-list ; (seit C++17)
typename - das Schlüsselwort typename kann nach Bedarf verwendet werden, um abhängige Namen aufzulösen, wenn die using-Deklaration einen Member-Typ aus einer Basisklasse in eine Klassen-Template einführt
nested-name-specifier - eine Folge von Namen und Bereichsauflösungsoperatoren :: , die mit einem Bereichsauflösungsoperator endet. Ein einzelnes :: bezieht sich auf den globalen Namensraum.
unqualified-id - ein id-Ausdruck
declarator-list - kommagetrennte Liste von einem oder mehreren Deklaratoren der Form typename (optional) nested-name-specifier unqualified-id . Ein Deklarator kann von einer Auslassungspunkten gefolgt werden, um eine Paketentfaltung anzuzeigen, obwohl diese Form nur in abgeleiteten Klassendefinitionen sinnvoll ist

Using-Deklarationen können verwendet werden, um Namespace-Mitglieder in andere Namespaces und Blockbereiche einzuführen, oder um Basisklassenmitglieder in abgeleitete Klassendefinitionen einzuführen , oder um Enumeratoren in Namespaces, Block- und Klassenbereiche einzuführen (since C++20) .

Eine using-Deklaration mit mehr als einem using-Deklarator entspricht einer entsprechenden Folge von using-Deklarationen mit jeweils einem using-Deklarator.

(since C++17)

Für die Verwendung in abgeleiteten Klassendefinitionen, siehe using declaration .

Durch eine using-Deklaration in einen Namensbereich eingeführte Namen können wie alle anderen Namen verwendet werden, einschließlich qualifizierter Suche aus anderen Geltungsbereichen:

void f();
namespace A
{
    void g();
}
namespace X
{
    using ::f;        // globales f ist nun sichtbar als ::X::f
    using A::g;       // A::g ist nun sichtbar als ::X::g
    using A::g, A::g; // (C++17) OK: Doppeldeklaration im Namensbereich erlaubt
}
void h()
{
    X::f(); // ruft ::f auf
    X::g(); // ruft A::g auf
}

Wenn nach der Verwendung einer using-Deklaration, um ein Member aus einem Namespace zu übernehmen, der Namespace erweitert wird und zusätzliche Deklarationen für denselben Namen eingeführt werden, werden diese zusätzlichen Deklarationen nicht durch die using-Deklaration sichtbar (im Gegensatz zur using-Direktive). Eine Ausnahme besteht, wenn eine using-Deklaration ein Klassentemplate benennt: Partielle Spezialisierungen, die später eingeführt werden, sind effektiv sichtbar, weil ihr Lookup über das primäre Template erfolgt.

namespace A
{
    void f(int);
}
using A::f; // ::f ist jetzt ein Synonym für A::f(int)
namespace A       // Namensraumerweiterung
{
    void f(char); // ändert nicht, was ::f bedeutet
}
void foo()
{
    f('a'); // ruft f(int) auf, obwohl f(char) existiert.
}
void bar()
{
    using A::f; // dieses f ist ein Synonym für sowohl A::f(int) als auch A::f(char)
    f('a');     // ruft f(char) auf
}

Using-Deklarationen können keine template-id oder einen Namensraum benennen , oder einen scoped enumerator (bis C++20) . Jeder Deklarator in einer Using-Deklaration führt einen und nur einen Namen ein, zum Beispiel führt eine Using-Deklaration für eine enumeration keine ihrer Enumeratoren ein.

Alle Einschränkungen für reguläre Deklarationen derselben Namen, Verdeckungs- und Überladungsregeln gelten für using-Deklarationen:

namespace A
{
    int x;
}
namespace B
{
    int i;
    struct g {};
    struct x {};
    void f(int);
    void f(double);
    void g(char); // OK: Funktionsname g verdeckt struct g
}
void func()
{
    int i;
    using B::i;   // Fehler: i wurde zweimal deklariert
    void f(char);
    using B::f;   // OK: f(char), f(int), f(double) sind Überladungen
    f(3.5);       // ruft B::f(double) auf
    using B::g;
    g('a');       // ruft B::g(char) auf
    struct g g1;  // deklariert g1 mit Typ struct B::g
    using B::x;
    using A::x;   // OK: verdeckt struct B::x
    x = 99;       // weist A::x zu
    struct x x1;  // deklariert x1 mit Typ struct B::x
}

Wenn eine Funktion durch eine using-Deklaration eingeführt wurde, ist die Deklaration einer Funktion mit demselben Namen und Parameterliste fehlerhaft (es sei denn, die Deklaration ist für dieselbe Funktion). Wenn eine Funktionsvorlage durch eine using-Deklaration eingeführt wurde, ist die Deklaration einer Funktionsvorlage mit demselben Namen, Parametertypliste, Rückgabetyp und Template-Parameterliste fehlerhaft. Zwei using-Deklarationen können Funktionen mit demselben Namen und derselben Parameterliste einführen, aber wenn ein Aufruf dieser Funktion versucht wird, ist das Programm fehlerhaft.

namespace B
{
    void f(int);
    void f(double);
}
namespace C
{
    void f(int);
    void f(double);
    void f(char);
}
void h()
{
    using B::f;  // führt B::f(int), B::f(double) ein
    using C::f;  // führt C::f(int), C::f(double) und C::f(char) ein
    f('h');      // ruft C::f(char) auf
    f(1);        // Fehler: B::f(int) oder C::f(int)?
    void f(int); // Fehler: f(int) kollidiert mit C::f(int) und B::f(int)
}

Wenn eine Entität deklariert, aber nicht in einem inneren Namespace definiert wird, und dann durch eine using-Deklaration im äußeren Namespace deklariert wird, und anschließend eine Definition im äußeren Namespace mit demselben unqualifizierten Namen erscheint, ist diese Definition ein Mitglied des äußeren Namespace und kollidiert mit der using-Deklaration:

namespace X
{
    namespace M
    {
        void g(); // deklariert, aber definiert nicht X::M::g()
    }
    using M::g;
    void g();     // Fehler: Versuch X::g zu deklarieren, was mit X::M::g() kollidiert
}

Allgemeiner gesagt, eine Deklaration, die in einem beliebigen Namensbereichs-Scope erscheint und einen Namen mit einem unqualifizierten Bezeichner einführt, führt immer ein Mitglied in den Namensbereich ein, in dem sie sich befindet, und nicht in einen anderen Namensbereich. Die Ausnahmen sind explizite Instanziierungen und explizite Spezialisierungen eines primären Templates, das in einem inline-Namensbereich definiert ist: Da sie keinen neuen Namen einführen, können sie unqualified-id in einem umschließenden Namensbereich verwenden.

Using-Direktiven

Eine using-directive ist eine block-declaration mit folgender Syntax:

attr  (optional) using namespace nested-name-specifier  (optional) namespace-name ; (1)
attr - (since C++11) beliebige Anzahl von Attributen , die auf diese using-Direktive anwendbar sind
nested-name-specifier - eine Folge von Namen und Bereichsauflösungsoperatoren :: , die mit einem Bereichsauflösungsoperator endet. Ein einzelnes :: bezieht sich auf den globalen Namensraum. Bei der Suche nach den Namen in dieser Folge berücksichtigt lookup nur Namespace-Deklarationen
namespace-name - ein Name eines Namespace. Bei der Suche nach diesem Namen berücksichtigt lookup nur Namespace-Deklarationen

Using-Directives sind nur im Namespace- Scope und im Block-Scope erlaubt. Vom Standpunkt des unqualified name lookup aus betrachtet, ist für jeden Namen nach einer Using-Directive und bis zum Ende des Scopes, in dem sie erscheint, jeder Name aus dem namespace-name sichtbar, als ob er im nächstgelegenen einschließenden Namespace deklariert wäre, der sowohl die Using-Directive als auch den namespace-name enthält.

Die Using-Direktive fügt dem deklarativen Bereich, in dem sie erscheint, keine Namen hinzu (im Gegensatz zur Using-Deklaration) und verhindert daher nicht, dass identische Namen deklariert werden.

Using-Direktiven sind transitiv für die Zwecke der unqualified lookup : Wenn ein Gültigkeitsbereich eine Using-Direktive enthält, die einen namespace-name benennt, der selbst Using-Direktiven für einen anderen namespace-name-2 enthält, ist der Effekt derselbe, als ob die Using-Direktiven aus dem zweiten Namespace im ersten erscheinen. Die Reihenfolge, in der diese transitiven Namespaces auftreten, beeinflusst die Namenssuche nicht.

namespace A
{
    int i;
}
namespace B
{
    int i;
    int j;
    namespace C
    {
        namespace D
        {
            using namespace A;
            // Namen aus A werden in D "injiziert".
            // Unqualifizierte Namenssuche in D betrachtet diese Namen als im gleichen
            // Gültigkeitsbereich wie der globale Bereich (z.B. für Namensverdeckung).
            // Qualifizierte Suche mit Bezug auf D (D::name für einen Namen)
            // wird denselben Namen finden wie unqualifizierte Suche in D.
            int j;
            int k;
            int a = i;   // i ist B::i, weil A::i durch B::i verdeckt wird
            int b = ::i; // Fehler: Es gibt immer noch kein i im globalen Namensraum
        }
        using namespace D; // Namen aus D und A werden in C injiziert
        int k = 89; // OK, einen Namen zu deklarieren, der identisch mit einem durch using eingeführten ist
        int l = k;  // Mehrdeutig: C::k oder D::k
        int m = i;  // ok: B::i verdeckt A::i
        int n = j;  // ok: D::j verdeckt B::j
    }
}
// Dies sind alle äquivalente Definitionen:
int t0 = B::i;
int t1 = B::C::a;
int t2 = B::C::D::a;

Wenn nach einer using-Directive zur Nominierung eines Namespaces der Namespace erweitert wird und zusätzliche Member und/oder using-Directives hinzugefügt werden, sind diese zusätzlichen Member und die zusätzlichen Namespaces durch die using-Directive sichtbar (im Gegensatz zur using-Deklaration)

namespace D
{
    int d1;
    void f(char);
}
using namespace D; // führt D::d1, D::f, D::d2, D::f,
                   // E::e und E::f in den globalen Namensraum ein!
int d1;            // OK: kein Konflikt mit D::d1 bei der Deklaration
namespace E
{
    int e;
    void f(int);
}
namespace D            // Namensraumerweiterung
{
    int d2;
    using namespace E; // transitive using-Direktive
    void f(int);
}
void f()
{
    d1++;    // Fehler: mehrdeutig ::d1 oder D::d1?
    ::d1++;  // OK
    D::d1++; // OK
    d2++;    // OK, d2 ist D::d2
    e++;     // OK: e ist E::e aufgrund transitiver using-Direktive
    f(1);    // Fehler: mehrdeutig: D::f(int) oder E::f(int)?
    f('a');  // OK: die einzige f(char) ist D::f(char)
}

Hinweise

Die using-Direktive using namespace std ; in jedem Namespace-Bereich führt jeden Namen aus dem Namespace std in den globalen Namespace ein (da der globale Namespace der nächstgelegene Namespace ist, der sowohl std als auch jeden benutzerdefinierten Namespace enthält), was zu unerwünschten Namenskonflikten führen kann. Dies und andere using-Direktiven werden im Allgemeinen als schlechte Praxis im Dateibereich einer Header-Datei betrachtet ( SF.7: Verwenden Sie using namespace nicht im globalen Bereich einer Header-Datei ).

Feature-Test-Makro Wert Std Feature
__cpp_namespace_attributes 201411L (C++17) Attribute für Namensräume

Schlüsselwörter

namespace , using , inline

Beispiel

Dieses Beispiel zeigt, wie ein Namespace verwendet wird, um eine Klasse zu erstellen, die bereits im std -Namespace benannt wurde.

#include <vector>
namespace vec
{
    template<typename T>
    class vector
    {
        // ...
    };
} // of vec
int main()
{
    std::vector<int> v1; // Standard vector.
    vec::vector<int> v2; // User defined vector.
    // v1 = v2;          // Error: v1 and v2 are different object's type.
    {
        using namespace std;
        vector<int> v3;  // Same as std::vector
        v1 = v3; // OK
    }
    {
        using vec::vector;
        vector<int> v4;  // Same as vec::vector
        v2 = v4; // OK
    }
}

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 101 C++98 das Programm ist fehlerhaft, wenn eine Funktionsdeklaration im Namensraum-
bereich oder Blockbereich und eine durch eine using-Deklaration eingeführte
Funktion dieselbe Funktion deklarieren (keine Mehrdeutigkeit)
erlaubt
CWG 373 C++98 Die Suche berücksichtigte Namensraumdeklarationen nur für
den letzten Namen im Operanden einer using-Direktive (was
suboptimal ist, da Klassen keine Namensräume enthalten können)
die Suchbeschränkung
gilt für alle Namen in den
Operanden von using-Direktiven
CWG 460 C++98 eine using-Deklaration konnte einen Namensraum benennen verboten
CWG 565 C++98 eine using-Deklaration kann keine Funktion einführen,
die mit einer anderen Funktion im selben Bereich identisch ist, aber
die Einschränkung wurde nicht auf Funktionsvorlagen angewendet
dieselbe Einschränkung auch
auf Funktionsvorlagen anwenden
CWG 986 C++98 using-Direktive war transitiv für qualifizierte Suche nur transitiv für unqualifizierte Suche
CWG 987 C++98 in einem verschachtelten Namensraum deklarierte Entitäten waren
auch Mitglieder des umschließenden Namensraums
verschachtelte Bereiche ausgeschlossen
CWG 1021 C++98 es war unklar, ob eine Entität, deren Definition
über eine using-Deklaration in einen Namensraum eingeführt wird,
als in diesem Namensraum definiert gilt
nicht in diesem Namensraum definiert
CWG 1838 C++98 unqualifizierte Definition in einem äußeren Namensraum
könnte eine Entität definieren, die in einem anderen Namensraum
deklariert, aber nicht definiert und durch using eingebunden wurde
unqualifizierte Definition
bezieht sich immer auf
ihren Namensraum
CWG 2155 C++98 die Lösung von CWG Issue 1838 wurde nicht
auf Klassen- und Aufzählungsdeklarationen angewendet
angewendet

Siehe auch

namespace alias erstellt einen Alias für einen bestehenden Namespace