Namensräume
Varianten
Aktionen

Namensräume

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Namensraumdeklaration  
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Namensräume bieten eine Methode, um Namenskonflikte in großen Projekten zu vermeiden.

Innerhalb eines Namensraumblocks deklarierte Entitäten werden einem Namensraum-Scope zugeordnet, was verhindert, dass sie mit gleichnamigen Entitäten in anderen Scopes verwechselt werden.

Außerhalb aller Namensraumblöcke deklarierte Entitäten gehören zum globalen Namensraum. Der globale Namensraum gehört zum globalen Scope und kann explizit mit einem führenden :: angesprochen werden. Obwohl er keine Deklaration hat, ist der globale Namensraum kein namensloser Namensraum.

Mehrere Namensraumblöcke mit demselben Namen sind erlaubt. Alle Deklarationen innerhalb dieser Blöcke werden im selben Namensraum-Scope deklariert.

Inhalt

[bearbeiten] Syntax

namespace ns-name { declarations } (1)
inline namespace ns-name { declarations } (2) (seit C++11)
namespace { declarations } (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 { declarations } (8) (seit C++17)
namespace ns-name :: inline member-name { declarations } (9) (seit C++20)
1) Definition eines benannten Namensraums für den Namensraum ns-name.
2) Definition eines Inline-Namensraums für den Namensraum ns-name. Deklarationen innerhalb von ns-name sind in seinem umgebenden Namensraum sichtbar.
3) Definition eines namenslosen Namensraums. Seine Mitglieder haben einen potenziellen Scope von ihrem Deklarationspunkt bis zum Ende der Übersetzungseinheit und haben eine interne Bindung.
4) Namensraumnamen (zusammen mit Klassennamen) können auf der linken Seite des Scope-Auflösungsoperators als Teil der qualifizierten Namenssuche erscheinen.
5) Using-Direktive: Aus der Sicht der nicht-qualifizierten Namenssuche für jeden Namen nach einer Using-Direktive und bis zum Ende des Scopes, in dem sie erscheint, ist jeder Name aus ns-name sichtbar, als ob er im nächstgelegenen umgebenden Namensraum deklariert worden wäre, der sowohl die Using-Direktive als auch ns-name enthält.
6) Using-Deklaration: macht das Symbol member-name aus dem Namensraum ns-name für die nicht-qualifizierte Suche zugänglich, als ob es im selben Klassen-, Block- oder Namensraum-Scope deklariert worden wäre, in dem diese Using-Deklaration erscheint.
7) namespace-alias-definition: macht name zu einem Synonym für einen anderen Namensraum: siehe Namensraum-Alias.
8) verschachtelte Namensraumdefinition: namespace A::B::C { ... } ist äquivalent zu namespace A { namespace B { namespace C { ... } } }.
9) verschachtelte Inline-Namensraumdefinition: namespace A::B::inline C { ... } ist äquivalent zu namespace A::B { inline namespace C { ... } }. inline kann vor jedem Namensraum-Namen außer dem ersten stehen: namespace A::inline B::C {} ist äquivalent zu namespace A { inline namespace B { namespace C {} } }.

[bearbeiten] Erklärung

[bearbeiten] Namensräume

inline(optional) namespace attr (optional) identifier { namespace-body }
inline - (seit C++11) falls vorhanden, macht dies einen Inline-Namensraum (siehe unten). Kann nicht bei der extension-namespace-definition vorkommen, wenn die original-namespace-definition nicht inline verwendet hat.
attr - (seit C++17) optionale Sequenz von beliebig vielen Attributen
identifier - entweder
  • ein bisher unbenutzter Bezeichner, in diesem Fall ist dies eine original-namespace-definition;
  • der Name eines Namensraums, in diesem Fall ist dies eine extension-namespace-definition;
  • eine durch :: getrennte Sequenz von umgebenden Namensraum-Spezifizierern, die mit einem identifier endet, in diesem Fall ist dies eine nested-namespace-definition.
(seit C++17)
namespace-body - möglicherweise leere Sequenz von Deklarationen jeglicher Art (einschließlich Klassen- und Funktionsdefinitionen sowie verschachtelter Namensräume)

Namensraumdefinitionen sind nur im Namensraum-Scope, einschließlich des globalen Scopes, erlaubt.

Um einen bestehenden Namensraum erneut zu öffnen (formal, um eine extension-namespace-definition zu sein), muss die Suche nach dem identifier, der in der Namensraumdefinition verwendet wird, zu einem Namensraum-Namen (nicht zu einem Namensraum-Alias) aufgelöst werden, der als Mitglied des umgebenden Namensraums oder eines Inline-Namensraums innerhalb eines umgebenden Namensraums deklariert wurde.

Der namespace-body definiert einen Namensraum-Scope, der die Namenssuche beeinflusst.

Alle Namen, die durch die Deklarationen innerhalb von namespace-body (einschließlich verschachtelter Namensraumdefinitionen) eingeführt werden, werden zu Mitgliedern des Namensraums identifier, unabhängig davon, ob diese Namensraumdefinition die ursprüngliche Namensraumdefinition ist (die identifier eingeführt hat) oder eine erweiterte Namensraumdefinition (die den bereits definierten Namensraum "wiedereröffnet").

Ein Namensraummitglied, das innerhalb eines Namensraumkörpers deklariert wurde, kann außerhalb davon durch explizite Qualifizierung definiert oder neu deklariert werden.

namespace Q
{
    namespace V   // V is a member of Q, and is fully defined within Q
    { // namespace Q::V { // C++17 alternative to the lines above
        class C { void m(); }; // C is a member of V and is fully defined within V
                               // C::m is only declared
        void f(); // f is a member of V, but is only declared here
    }
 
    void V::f() // definition of V's member f outside of V
                // f's enclosing namespaces are still the global namespace, Q, and Q::V
    {
        extern void h(); // This declares ::Q::V::h
    }
 
    void V::C::m() // definition of V::C::m outside of the namespace (and the class body)
                   // enclosing namespaces are the global namespace, Q, and Q::V
    {}
}

Definitionen und Neudeklarationen außerhalb des Namensraums sind nur erlaubt

  • nach dem Deklarationspunkt,
  • im Namensraum-Scope und
  • in Namensräumen, die den ursprünglichen Namensraum einschließen (einschließlich des globalen Namensraums).

Außerdem müssen sie die Syntax eines qualifizierten Identifikators verwenden.

namespace Q
{
    namespace V    // original-namespace-definition for V
    {
        void f();  // declaration of Q::V::f
    }
 
    void V::f() {} // OK
    void V::g() {} // Error: g() is not yet a member of V
 
    namespace V    // extension-namespace-definition for V
    {
        void g();  // declaration of Q::V::g
    }
}
 
namespace R           // not an enclosing namespace for Q
{
    void Q::V::g() {} // Error: cannot define Q::V::g inside R
}
 
void Q::V::g() {}     // OK: global namespace encloses Q

Namen, die durch friend-Deklarationen innerhalb einer nicht-lokalen Klasse X eingeführt werden, werden zu Mitgliedern des innersten umgebenden Namensraums von X, sind aber für die normale Namenssuche (weder unqualifiziert noch qualifiziert) nicht sichtbar, es sei denn, eine übereinstimmende Deklaration wird im Namensraum-Scope bereitgestellt, entweder vor oder nach der Klassendefinition. Ein solcher Name kann durch ADL gefunden werden, die sowohl Namensräume als auch Klassen berücksichtigt.

Nur der innerste umgebende Namensraum wird bei solchen friend-Deklarationen berücksichtigt, um zu entscheiden, ob der Name mit einem zuvor deklarierten Namen kollidiert.

void h(int);
namespace A
{
    class X
    {
        friend void f(X);       // A::f is a friend
 
        class Y
        {
            friend void g();    // A::g is a friend
            friend void h(int); // A::h is a friend, no conflict with ::h
        };
    };
    // A::f, A::g and A::h are not visible at namespace scope
    // even though they are members of the namespace A
 
    X x;
    void g()  // definition of A::g
    {
        f(x); // A::X::f is found through ADL
    }
 
    void f(X) {}   // definition of A::f
    void h(int) {} // definition of A::h
    // A::f, A::g and A::h are now visible at namespace scope
    // and they are also friends of A::X and A::X::Y
}

Inline-Namensräume

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

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

  • Eine using-directive, die den Inline-Namensraum benennt, wird implizit in den umgebenden Namensraum eingefügt (ähnlich der impliziten using-directive für den namenslosen Namensraum).
  • Bei der argument-abhängigen Suche werden beim Hinzufügen eines Namensraums zum Satz der assoziierten Namensräume auch dessen Inline-Namensräume hinzugefügt, und wenn ein Inline-Namensraum zur Liste der assoziierten Namensräume hinzugefügt wird, wird auch sein umgebender Namensraum hinzugefügt.
  • Jedes Mitglied eines Inline-Namensraums kann partiell spezialisiert, explizit instanziiert oder explizit spezialisiert werden, als wäre es ein Mitglied des umgebenden Namensraums.
  • Die qualifizierte Namenssuche, die den umgebenden Namensraum untersucht, schließt die Namen aus den Inline-Namensräumen ein, auch wenn derselbe Name im umgebenden Namensraum 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 ermöglicht die Versionsverwaltung von Bibliotheken: unterschiedliche Implementierungen einer Bibliotheks-Vorlage können in verschiedenen Inline-Namensräumen definiert werden, während es dem Benutzer immer noch erlaubt ist, den übergeordneten Namensraum mit einer expliziten Spezialisierung der Primär-Vorlage zu erweitern.

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)

[bearbeiten] Namenslose Namensräume

Die unnamed-namespace-definition ist eine Namensraumdefinition der Form

inline(optional) namespace attr (optional) { namespace-body }
inline - (seit C++11) falls vorhanden, macht dies einen Inline-Namensraum.
attr - (seit C++17) optionale Sequenz von beliebig vielen Attributen

Diese Definition wird als Definition eines Namensraums mit einem eindeutigen Namen behandelt, und eine using-directive im aktuellen Scope, die diesen namenslosen Namensraum nominiert (Hinweis: die implizit hinzugefügte using-directive macht den Namensraum für die qualifizierte Namenssuche und nicht-qualifizierte Namenssuche verfügbar, aber nicht für die argument-abhängige Suche). Der eindeutige Name ist im gesamten Programm eindeutig, aber innerhalb einer Übersetzungseinheit entspricht jede namenslose Namensraumdefinition demselben eindeutigen Namen: mehrere namenslose Namensraumdefinitionen im selben Scope bezeichnen denselben namenslosen Namensraum.

namespace
{
    int i; // defines ::(unique)::i
}
 
void f()
{
    i++;   // increments ::(unique)::i
}
 
namespace A
{
    namespace
    {
        int i;        // A::(unique)::i
        int j;        // A::(unique)::j
    }
 
    void g() { i++; } // A::(unique)::i++
}
 
using namespace A; // introduces all names from A into global namespace
 
void h()
{
    i++;    // error: ::(unique)::i and ::A::(unique)::i are both in scope
    A::i++; // ok, increments ::A::(unique)::i
    j++;    // ok, increments ::A::(unique)::j
}

Auch wenn Namen in einem namenslosen Namensraum mit externer Bindung deklariert werden können, sind sie von anderen Übersetzungseinheiten aus nie zugänglich, da ihr Namensraumname eindeutig ist.

(bis C++11)

Namenslose Namensräume sowie alle Namensräume, die direkt oder indirekt innerhalb eines namenslosen Namensraums deklariert werden, haben eine interne Bindung, was bedeutet, dass jeder Name, der innerhalb eines namenslosen Namensraums deklariert wird, eine interne Bindung hat.

(seit C++11)

[bearbeiten] Using-Deklarationen

Führt einen Namen, der an anderer Stelle definiert ist, in den Deklarationsbereich 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 einer Klassenvorlage einführt.
nested-name-specifier - eine Sequenz von Namen und Scope-Auflösungsoperatoren ::, die mit einem Scope-Auflösungsoperator endet. Ein einzelnes :: bezieht sich auf den globalen Namensraum.
unqualified-id - ein id-expression
declarator-list - durch Kommata getrennte Liste von einem oder mehreren Deklaratoren der Form typename(optional) nested-name-specifier unqualified-id. Ein Deklarator kann von einer Ellipse gefolgt werden, um eine Pack-Erweiterung anzuzeigen, obwohl diese Form nur in abgeleiteten Klassendefinitionen sinnvoll ist.

Using-Deklarationen können verwendet werden, um Namensraummitglieder in andere Namensräume und Block-Scopes einzuführen, oder um Basisklassenmitglieder in abgeleitete Klassendefinitionen einzuführen, oder um Enumerator in Namensräume, Block- und Klassenscopes einzuführen(seit C++20).

Eine Using-Deklaration mit mehr als einem Using-Deklarator ist äquivalent zu einer entsprechenden Sequenz von Using-Deklarationen mit einem Using-Deklarator.

(seit C++17)

Für die Verwendung in abgeleiteten Klassendefinitionen siehe Using-Deklaration.

In einen Namensraum-Scope eingeführte Namen durch eine Using-Deklaration können wie andere Namen verwendet werden, einschließlich qualifizierter Suche aus anderen Scopes.

void f();
namespace A
{
    void g();
}
 
namespace X
{
    using ::f;        // global f is now visible as ::X::f
    using A::g;       // A::g is now visible as ::X::g
    using A::g, A::g; // (C++17) OK: double declaration allowed at namespace scope
}
 
void h()
{
    X::f(); // calls ::f
    X::g(); // calls A::g
}

Wenn nach der Verwendung einer Using-Deklaration, um ein Mitglied aus einem Namensraum zu übernehmen, der Namensraum erweitert und zusätzliche Deklarationen für denselben Namen eingeführt werden, werden diese zusätzlichen Deklarationen nicht über die Using-Deklaration sichtbar (im Gegensatz zur Using-Direktive). Eine Ausnahme bildet die Benennung einer Klassenvorlage durch eine Using-Deklaration: später eingeführte partielle Spezialisierungen sind effektiv sichtbar, da ihre Suche über die Primärvorlage erfolgt.

namespace A
{
    void f(int);
}
using A::f; // ::f is now a synonym for A::f(int)
 
namespace A       // namespace extension
{
    void f(char); // does not change what ::f means
}
 
void foo()
{
    f('a'); // calls f(int), even though f(char) exists.
}
 
void bar()
{
    using A::f; // this f is a synonym for both A::f(int) and A::f(char)
    f('a');     // calls f(char)
}

Using-Deklarationen können keine template-id, keine Namensräume, und keine Scope-basierten Aufzählungen benennen(bis C++20). Jeder Deklarator in einer Using-Deklaration führt genau einen Namen ein, zum Beispiel führt eine Using-Deklaration für eine Aufzählung keine ihrer Aufzähler ein.

Alle Einschränkungen für reguläre Deklarationen derselben Namen, Hiding 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: function name g hides struct g
}
 
void func()
{
    int i;
    using B::i;   // error: i declared twice
 
    void f(char);
    using B::f;   // OK: f(char), f(int), f(double) are overloads
    f(3.5);       // calls B::f(double)
 
    using B::g;
    g('a');       // calls B::g(char)
    struct g g1;  // declares g1 to have type struct B::g
 
    using B::x;
    using A::x;   // OK: hides struct B::x
    x = 99;       // assigns to A::x
    struct x x1;  // declares x1 to have type struct B::x
}

Wenn eine Funktion durch eine Using-Deklaration eingeführt wurde, ist die Deklaration einer Funktion mit demselben Namen und derselben Parameterliste fehlerhaft (es sei denn, die Deklaration betrifft dieselbe Funktion). Wenn eine Funktionvorlage durch eine Using-Deklaration eingeführt wurde, ist die Deklaration einer Funktionvorlage mit demselben Namen, derselben Parameterliste, demselben Rückgabetyp und derselben Vorlagenparameterliste 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;  // introduces B::f(int), B::f(double)
    using C::f;  // introduces C::f(int), C::f(double), and C::f(char)
    f('h');      // calls C::f(char)
    f(1);        // error: B::f(int) or C::f(int)?
    void f(int); // error: f(int) conflicts with C::f(int) and B::f(int)
}

Wenn eine Entität in einem inneren Namensraum deklariert, aber nicht definiert ist, und dann durch eine Using-Deklaration im äußeren Namensraum deklariert wird, und dann eine Definition im äußeren Namensraum mit demselben nicht-qualifizierten Namen erscheint, ist diese Definition ein Mitglied des äußeren Namensraums und steht im Konflikt mit der Using-Deklaration.

namespace X
{
    namespace M
    {
        void g(); // declares, but doesn't define X::M::g()
    }
    using M::g;
 
    void g();     // Error: attempt to declare X::g which conflicts with X::M::g()
}

Allgemeiner gesagt, führt eine Deklaration, die in einem Namensraum-Scope erscheint und einen Namen mittels eines nicht-qualifizierten Identifikators einführt, immer ein Mitglied in den Namensraum ein, in dem sie sich befindet, und nicht in einen anderen Namensraum. Ausnahmen bilden explizite Instanziierungen und explizite Spezialisierungen einer Primärvorlage, die in einem Inline-Namensraum definiert ist: da sie keinen neuen Namen einführen, dürfen sie unqualified-id in einem umgebenden Namensraum verwenden.

[bearbeiten] Using-Direktiven

Eine using-directive ist eine block-declaration mit der folgenden Syntax

attr (optional) using namespace nested-name-specifier (optional) namespace-name ; (1)
attr - (seit C++11) beliebig viele Attribute, die für diese Using-Direktive gelten.
nested-name-specifier - eine Sequenz von Namen und Scope-Auflösungsoperatoren ::, die mit einem Scope-Auflösungsoperator endet. Ein einzelnes :: bezieht sich auf den globalen Namensraum. Bei der Suche nach den Namen in dieser Sequenz berücksichtigt die Suche nur Namensraumdeklarationen.
namespace-name - ein Name eines Namensraums. Bei der Suche nach diesem Namen berücksichtigt die Suche nur Namensraumdeklarationen.

Using-Direktiven sind nur im Namensraum- Scope und im Block-Scope erlaubt. Aus der Sicht der nicht-qualifizierten Namenssuche für jeden Namen nach einer Using-Direktive und bis zum Ende des Scopes, in dem sie erscheint, ist jeder Name aus namespace-name sichtbar, als ob er im nächstgelegenen umgebenden Namensraum deklariert worden wäre, der sowohl die Using-Direktive als auch namespace-name enthält.

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

Using-Direktiven sind für die Zwecke der nicht-qualifizierten Suche transitiv: Wenn ein Scope eine Using-Direktive enthält, die einen namespace-name nominiert, der selbst Using-Direktiven für einen bestimmten namespace-name-2 enthält, ist die Wirkung so, als ob die Using-Direktiven aus dem zweiten Namensraum innerhalb des ersten erscheinen würden. Die Reihenfolge, in der diese transitiven Namensräume auftreten, beeinflusst die Namenssuche nicht.

namespace A
{
    int i;
}
 
namespace B
{
    int i;
    int j;
 
    namespace C
    {
        namespace D
        {
            using namespace A;
            // Names from A are "injected" into D.
            // Unqualified lookup within D considers these names to have the same
            // scope as the global scope (e.g. for the purposes of name hiding).
            // Qualified lookup referring to D (D::name for some name)
            // will find the same name as unqualified lookup within D.
 
            int j;
            int k;
            int a = i;   // i is B::i, because A::i is hidden by B::i
            int b = ::i; // error: there is still no i in the global namespace
        }
 
        using namespace D; // names from D and A are injected into C
 
        int k = 89; // OK to declare name identical to one introduced by a using
        int l = k;  // ambiguous: C::k or D::k
        int m = i;  // ok: B::i hides A::i
        int n = j;  // ok: D::j hides B::j
    }
}
 
// These are all equivalent definitions:
int t0 = B::i;
int t1 = B::C::a;
int t2 = B::C::D::a;

Wenn nach der Verwendung einer Using-Direktive zur Nominierung eines Namensraums der Namensraum erweitert und zusätzliche Mitglieder und/oder Using-Direktiven hinzugefügt werden, sind diese zusätzlichen Mitglieder und die zusätzlichen Namensräume über die Using-Direktive sichtbar (im Gegensatz zur Using-Deklaration).

namespace D
{
    int d1;
    void f(char);
}
using namespace D; // introduces D::d1, D::f, D::d2, D::f,
                   // E::e, and E::f into global namespace!
 
int d1;            // OK: no conflict with D::d1 when declaring
 
namespace E
{
    int e;
    void f(int);
}
 
namespace D            // namespace extension
{
    int d2;
    using namespace E; // transitive using-directive
    void f(int);
}
 
void f()
{
    d1++;    // error: ambiguous ::d1 or D::d1?
    ::d1++;  // OK
    D::d1++; // OK
    d2++;    // OK, d2 is D::d2
 
    e++;     // OK: e is E::e due to transitive using
 
    f(1);    // error: ambiguous: D::f(int) or E::f(int)?
    f('a');  // OK: the only f(char) is D::f(char)
}

[bearbeiten] Notizen

Die Using-Direktive using namespace std; in einem beliebigen Namensraum-Scope führt jeden Namen aus dem Namensraum std in den globalen Namensraum ein (da der globale Namensraum der nächstgelegene Namensraum ist, der sowohl std als auch jeden benutzerdefinierten Namensraum enthält), was zu unerwünschten Namenskollisionen führen kann. Dies und andere Using-Direktiven gelten im Allgemeinen als schlechte Praxis im Dateiscope einer Header-Datei (SF.7: Schreiben Sie keine using namespace im globalen Scope einer Header-Datei).

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

[bearbeiten] Schlüsselwörter

namespace, using, inline

[bearbeiten] Beispiel

Dieses Beispiel zeigt, wie ein Namensraum verwendet wird, um eine Klasse zu erstellen, die bereits im Namensraum std 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
    }
}

[bearbeiten] Berichte über Fehler

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

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 101 C++98 das Programm ist fehlerhaft, wenn eine Funktionsdeklaration im Namensraum
Scope oder Block-Scope und eine Funktion, die durch eine
Using-Deklaration eingeführt wurde, dieselbe Funktion deklarieren (keine Mehrdeutigkeit).
erlaubt
CWG 373 C++98 die Suche berücksichtigte nur 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
identisch mit einer anderen Funktion im selben Scope ist, aber
die Einschränkung wurde nicht auf Funktionsvorlagen angewendet.
die gleiche Einschränkung anwenden
auf Funktionsvorlagen ebenso.
CWG 986 C++98 die Using-Direktive war transitiv für die qualifizierte Suche nur transitiv für die nicht-qualifizierte Suche
CWG 987 C++98 Entitäten, die in einem verschachtelten Namensraum deklariert wurden, waren
auch Mitglieder des umgebenden Namensraums.
verschachtelte Scopes ausgeschlossen
CWG 1021 C++98 Es war unklar, ob eine Entität, deren Definition
über eine Using-Deklaration in einen Namensraum eingeführt wurde,
als in diesem Namensraum definiert gilt.
nicht im Namensraum definiert
CWG 1838 C++98 eine nicht-qualifizierte Definition in einem äußeren Namensraum
konnte eine Entität definieren, die in einem
anderen Namensraum deklariert, aber nicht definiert und durch ein Using
nicht-qualifizierte Definition
bezieht sich immer auf
ihren Namensraum.
CWG 2155 C++98 die Auflösung von CWG-Problem 1838 wurde nicht
auf Klassen- und Aufzählungsdeklarationen angewendet.
angewendet

[bearbeiten] Siehe auch

Namensraum-Alias erstellt einen Alias für einen bestehenden Namensraum[bearbeiten]