Namensräume
Varianten
Aktionen

Gültigkeitsbereich

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
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
 
 

Jede Deklaration, die in einem C++-Programm erscheint, ist nur in bestimmten, möglicherweise nicht zusammenhängenden Geltungsbereichen  sichtbar.

Innerhalb eines Geltungsbereichs kann die nicht qualifizierte Namenssuche verwendet werden, um einen Namen mit seiner Deklaration zu verknüpfen.

Inhalt

[bearbeiten] Allgemein

Jedes Programm hat einen globalen Geltungsbereich , der das gesamte Programm enthält.

Jeder andere Geltungsbereich S wird durch eines der folgenden eingeführt:

(seit C++26)

S erscheint immer in einem anderen Geltungsbereich, der somit S enthält.

Ein umgebender Geltungsbereich an einem Programm-Punkt ist jeder Geltungsbereich, der ihn enthält; der kleinste solche Geltungsbereich wird als der direkte Geltungsbereich an diesem Punkt bezeichnet.

Ein Geltungsbereich liegt dazwischen einem Programm-Punkt P und einem Geltungsbereich S (der P nicht enthält), wenn er S ist oder S enthält, aber P nicht enthält.

Der Eltern-Geltungsbereich eines jeden Geltungsbereichs S, der kein Template-Parameter-Geltungsbereich ist, ist der kleinste Geltungsbereich, der S enthält und kein Template-Parameter-Geltungsbereich ist.

Sofern nicht anders angegeben

  • Eine Deklaration bewohnt den direkten Geltungsbereich an ihrem Lokus.
  • Der Ziel-Geltungsbereich einer Deklaration ist der Geltungsbereich, den sie bewohnt.
  • Alle Namen, die durch eine Deklaration (neu) eingeführt werden, sind in ihrem Ziel-Geltungsbereich an diese gebunden.

Eine Entität gehört zu einem Geltungsbereich S, wenn S der Ziel-Geltungsbereich einer Deklaration der Entität ist.

//                global  scope  scope
//                scope     S      T
int x;         //   ─┐                 // program point X
               //    │
{              //    │     ─┐
    {          //    │      │     ─┐
        int y; //    │      │      │   // program point Y
    }          //    │      │     ─┘
}              //   ─┘     ─┘

Im obigen Programm

  • Der globale Geltungsbereich, der Geltungsbereich S und der Geltungsbereich T enthalten den Programm-Punkt Y.
  • Mit anderen Worten, diese drei Geltungsbereiche sind alle umgebende Geltungsbereiche am Programm-Punkt Y.
  • Der globale Geltungsbereich enthält die Geltungsbereiche S und T, und der Geltungsbereich S enthält den Geltungsbereich T.
  • Daher ist der Geltungsbereich T der kleinste Geltungsbereich unter allen dreien, was bedeutet,
  • Der Geltungsbereich T ist der direkte Geltungsbereich am Programm-Punkt Y.
  • Die Deklaration der Variable y bewohnt den Geltungsbereich T an ihrem Lokus.
  • Der Geltungsbereich T ist der Ziel-Geltungsbereich der Deklaration von y.
  • Die Variable y gehört zum Geltungsbereich T.
  • Der Geltungsbereich S ist der Eltern-Geltungsbereich von Geltungsbereich T, und der globale Geltungsbereich ist der Eltern-Geltungsbereich von Geltungsbereich S.
  • Der Geltungsbereich S liegt zwischen dem Programm-Punkt X und dem Geltungsbereich T.

[bearbeiten] Block-Geltungsbereich

Jede

führt einen Block-Geltungsbereich ein, der die Anweisung oder den Handler umfasst.

Eine Variable, die zu einem Block-Geltungsbereich gehört, ist eine Blockvariable .

int i = 42;
int a[10];
 
for (int i = 0; i < 10; i++) // inner “i” inhabits the block scope
    a[i] = i;                // introduced by the for-statement
 
int j = i; // j = 42

Wenn die Deklaration einen Block-Geltungsbereich S bewohnt und eine Funktion deklariert oder den extern-Spezifizierer verwendet, darf die Deklaration nicht an ein benanntes Modul  gebunden sein(seit C++20), ist ihr Ziel-Geltungsbereich ein größerer umgebender Geltungsbereich (der innerste umgebende Namespace-Geltungsbereich), aber der Name wird in ihrem direkten Geltungsbereich S gebunden.

Wenn eine Deklaration, die keine namensunabhängige Deklaration ist und(seit C++26), die einen Namen im Block-Geltungsbereich S von

(seit C++11)
  • einer Teil-Anweisung einer Auswahl- oder Iterationsanweisung, die selbst keine Auswahl- oder Iterationsanweisung ist, oder
  • einem Handler eines Funktions-try-Blocks

potenziell kollidiert mit einer Deklaration, deren Ziel-Geltungsbereich der Eltern-Geltungsbereich von S ist, ist das Programm fehlerhaft.

if (int x = f())  // declares “x”
{ // the if-block is a substatement of the if-statement
    int x;        // error: redeclaration of “x”
}
else
{ // the else-block is also a substatement of the if-statement
    int x;        // error: redeclaration of “x”
}
 
void g(int i)
{
    extern int i; // error: redeclaration of “i”
}

[bearbeiten] Funktionsparameter-Geltungsbereich

Jede Parameterdeklaration P führt einen Funktionsparameter-Geltungsbereich ein, der P umfasst.

  • Wenn die Funktionsdeklaration eine Funktionsdefinition ist, wird der eingeführte Geltungsbereich bis zum Ende der Funktionsdefinition erweitert.
  • Andernfalls (die Funktionsdeklaration ist ein Funktionsprototyp), wird der eingeführte Geltungsbereich bis zum Ende des Funktionsdeklarators erweitert.
  • In beiden Fällen umfasst der Geltungsbereich nicht den Lokus der Funktionsdeklaration.
  • Wenn der deklarierte Parameter Teil der Parameterliste eines Lambda-Ausdrucks ist, wird der eingeführte Geltungsbereich bis zum Ende von { body } erweitert.
(seit C++11)
  • Wenn der deklarierte Parameter Teil der Parameterliste einer Deduktionshilfe ist, wird der eingeführte Geltungsbereich bis zum Ende dieser Deduktionshilfe erweitert.
(seit C++17)
  • Wenn der deklarierte Parameter Teil der Parameterliste eines requires-Ausdrucks ist, wird der eingeführte Geltungsbereich bis zum Ende von { requirement-seq } erweitert.
(seit C++20)
int f(int n) // the declaration of the parameter “n”
{            // introduces a function parameter scope
    /* ... */
}            // the function parameter scope ends here

Lambda-Geltungsbereich

Jeder Lambda-Ausdruck führt einen Lambda-Geltungsbereich ein, der unmittelbar nach [captures ] beginnt und bis zum Ende von { body } reicht.

Die Captures mit Initialisierungen eines Lambda-Ausdrucks E bewohnen den Lambda-Geltungsbereich, der von E eingeführt wird.

auto lambda = [x = 1, y]() // this lambda expression introduces a lambda scope,
{                          // it is the target scope of capture “x”
    /* ... */
};                         // the lambda scope ends before the semicolon
(seit C++14)

[bearbeiten] Namespace-Geltungsbereich

Jede Namespace-Definition für einen Namespace N führt einen Namespace-Geltungsbereich S ein, der die Deklarationen jeder Namespace-Definition für N umfasst.

Für jede Nicht-Friend-Neudeklaration oder Spezialisierung, deren Ziel-Geltungsbereich S ist oder von S umschlossen wird, sind die folgenden Teile ebenfalls in Geltungsbereich S enthalten:

  • Für eine Klassen- (oder Klassenvorlagen-) Neudeklaration oder Klassenvorlagenspezialisierung, der Teil nach ihrem class-head-name.
  • Für eine Aufzählungs- Neudeklaration, der Teil nach ihrem enum-head-name.
  • Für jede andere Neudeklaration oder Spezialisierung, der Teil nach dem unqualified-id oder qualified-id des Deklarators.

Der globale Geltungsbereich ist der Namespace-Geltungsbereich des globalen Namespaces.

namespace V   // the namespace definition of “V”
{             // introduces a namespace scope “S”
    // the first part of scope “S” begins here
    void f();
    // the first part of scope “S” ends here
}
 
void V::f()   // the portion after “f” is also a part of scope “S”
{
    void h(); // declares V::h
}             // the second part of scope “S” ends here

[bearbeiten] Klassen-Geltungsbereich

Jede Deklaration einer Klasse oder Klassenvorlage C führt einen Klassen-Geltungsbereich S ein, der die member-specification der Klassendefinition von C umfasst.

Für jede Nicht-Friend-Neudeklaration oder Spezialisierung, deren Ziel-Geltungsbereich S ist oder von S umschlossen wird, sind die folgenden Teile ebenfalls in Geltungsbereich S enthalten:

  • Für eine Klassen- (oder Klassenvorlagen-) Neudeklaration oder Klassenvorlagenspezialisierung, der Teil nach ihrem class-head-name.
  • Für eine Aufzählungs- Neudeklaration, der Teil nach ihrem enum-head-name.
  • Für jede andere Neudeklaration oder Spezialisierung, der Teil nach dem unqualified-id oder qualified-id des Deklarators.
class C       // the class definition of “C”
{             // introduces a class scope “S”
    // the first part of scope “S” begins here
    void f();
    // the first part of scope “S” ends here
}
 
void C::f()   // the portion after “f” is also a part of scope “S”
{
    /* ... */
}             // the second part of scope “S” ends here

[bearbeiten] Aufzählungs-Geltungsbereich

Jede Deklaration einer Aufzählung E führt einen Aufzählungs-Geltungsbereich ein, der die enumerator-list der Nicht-Opaken(seit C++11) Aufzählungsdeklaration von E (falls vorhanden) umfasst.

enum class E // the enumeration declaration of “E”
{            // introduces an enumeration scope “S”
    // scope “S” begins here
    e1, e2, e3
    // scope “S” ends here
}

[bearbeiten] Template-Parameter-Geltungsbereich

Jeder Template-Template-Parameter führt einen Template-Parameter-Geltungsbereich ein, der die gesamte Template-Parameterliste und die requires-Klauseln(seit C++20) dieses Template-Template-Parameters umfasst.

Jede Template-Deklaration D führt einen Template-Parameter-Geltungsbereich S ein, der vom Beginn der Template-Parameterliste von D bis zum Ende von D reicht. Jede Deklaration außerhalb der Template-Parameterliste, die S bewohnen würde, bewohnt stattdessen denselben Geltungsbereich wie D.

Nur Template-Parameter gehören zu einem Template-Parameter-Geltungsbereich, und nur Template-Parameter-Geltungsbereiche haben einen Template-Parameter-Geltungsbereich als Eltern-Geltungsbereich.

// the class template declaration of “X”
// introduces a template parameter scope “S1”
template
<
    // scope “S1” begins here
    template // the template template parameter “T”
             // introduces another template parameter scope “S2”
    <
        typename T1
        typename T2
    > requires std::convertible_from<T1, T2> // scope “S2” ends here
    class T,
    typename U
>
class X; // scope “S1” ends before the semicolon
 
namespace N
{
    template <typename T>
    using A = struct X; // “X” inhabits the same scope as template
                        // declaration, namely the scope of “N”
}

Vertrags-Assertion-Geltungsbereich

Jede Vertrags-Assertion C führt einen Vertrags-Assertion-Geltungsbereich ein, der C umfasst.

Wenn eine Nachbedingungs-Assertion einen Identifikator hat, der nicht namensunabhängig ist, und die Nachbedingungs-Assertion mit einer Funktion func verbunden ist, die potenziell kollidiert mit einer Deklaration D, deren Ziel-Geltungsbereich einer der folgenden Geltungsbereiche ist, ist das Programm fehlerhaft:

  • Der Funktionsparameter-Geltungsbereich von func.
  • Wenn D mit einem Lambda-Ausdruck verbunden ist, der am nächsten liegende umgebende Lambda-Geltungsbereich der Vorbedingungs-Assertion.
(seit C++26)

[bearbeiten] Punkt der Deklaration

Im Allgemeinen ist ein Name nach dem Lokus seiner ersten Deklaration sichtbar, der sich wie folgt befindet:

Der Lokus eines Namens, der in einer einfachen Deklaration deklariert wird, liegt unmittelbar nach dem Deklarator dieses Namens und vor seinem Initialisierer, falls vorhanden.

int x = 32; // outer x is in scope
 
{
    int x = x; // inner x is in scope before the initializer (= x)
               // this does not initialize inner x with the value of outer x (32),
               // this initializes inner x with its own (indeterminate) value
}
 
std::function<int(int)> f = [&](int n){ return n > 1 ? n * f(n - 1) : n; };
// the name of the function f is in scope in the lambda and can
// be correctly captured by reference, giving a recursive function
const int x = 2; // outer x is in scope
 
{
    int x[x] = {}; // inner x is in scope before the initializer (= {}),
                   // but after the declarator (x[x])
                   // in the declarator, outer x is still in scope
                   // this declares an array of 2 int
}

Der Lokus einer Klassen- oder Klassenvorlagendeklaration liegt unmittelbar nach dem Bezeichner, der die Klasse (oder die template-id, die die Templatespezialisierung benennt) in ihrem Klassen-Head benennt. Der Klassen- oder Klassenvorlagenname ist in der Liste der Basisklassen bereits im Geltungsbereich.

struct S: std::enable_shared_from_this<S> {}; // S is in scope at the colon

Der Lokus eines Aufzählungsspezifizierers oder einer opaken Aufzählungsdeklaration(seit C++11) liegt unmittelbar nach dem Bezeichner, der die Aufzählung benennt.

enum E : int // E is in scope at the colon
{
    A = sizeof(E)
};

Der Lokus einer Typ-Alias- oder Aliasvorlagendeklaration liegt unmittelbar nach dem Type-Id, auf das sich der Alias bezieht.

using T = int; // outer T is in scope at the semicolon
 
{
    using T = T*; // inner T is in scope at the semicolon,
                  // outer T is still in scope before the semicolon
                  // same as T = int*
}

Der Lokus für einen Deklarator in einer using-Deklaration, die keinen Konstruktor benennt, liegt unmittelbar nach dem Deklarator.

template<int N>
class Base
{
protected:
    static const int next = N + 1;
    static const int value = N;
};
 
struct Derived: Base<0>, Base<1>, Base<2>
{
    using Base<0>::next,     // next is in scope at the comma
          Base<next>::value; // Derived::value is 1
};

Der Lokus eines Enumerators liegt unmittelbar nach seiner Definition (nicht vor dem Initialisierer, wie es bei Variablen der Fall ist).

const int x = 12;
 
{
    enum
    {
        x = x + 1, // enumerator x is in scope at the comma,
                   // outer x is in scope before the comma,
                   // enumerator x is initialized to 13
        y = x + 1  // y is initialized to 14
    };
}

Der Lokus eines eingeschleusten Klassennamens liegt unmittelbar nach der öffnenden geschweiften Klammer seiner Klassen- (oder Klassenvorlagen-) Definition.

template<typename T>
struct Array
//  : std::enable_shared_from_this<Array> // error: the injected class name is not in scope
    : std::enable_shared_from_this< Array<T> > // OK: the template-name Array is in scope
{ // the injected class name Array is now in scope as if a public member name
    Array* p; // pointer to Array<T>
};

Der Lokus der impliziten Deklaration für eine funktionslokale vordefinierte Variable __func__ liegt unmittelbar vor dem Funktionskörper einer Funktionsdefinition.

(seit C++11)


Der Lokus einer strukturierten Bindungsdeklaration liegt unmittelbar nach der identifier-list, aber strukturierte Bindungsinitialisierer dürfen keine der deklarierten Namen referenzieren.

(seit C++17)


Der Lokus der Variable oder der strukturierten Bindungen(seit C++17), die in der range-declaration einer range-for-Schleife deklariert werden, liegt unmittelbar nach dem range-expression.

std::vector<int> x;
 
for (auto x : x) // vector x is in scope before the closing parenthesis,
                 // auto x is in scope at the closing parenthesis
{
    // the auto x is in scope
}
(seit C++11)

Der Lokus eines Template-Parameters liegt unmittelbar nach seinem vollständigen Template-Parameter (einschließlich des optionalen Standardarguments).

typedef unsigned char T;
 
template<
    class T = T, // template parameter T is in scope at the comma,
                 // typedef name of unsigned char is in scope before the comma
    T // template parameter T is in scope
    N = 0
>
struct A
{
};

Der Lokus einer Nachbedingungs-Assertion mit einem Identifikator liegt unmittelbar nach ihrem :.

(seit C++26)


Der Lokus einer Konzeptdefinition liegt unmittelbar nach dem Konzeptnamen, aber Konzeptdefinitionen dürfen den zu deklarierenden Konzeptnamen nicht referenzieren.

(seit C++20)

Der Lokus einer benannten Namespace-Definition liegt unmittelbar nach dem Namespace-Namen.

[bearbeiten] Fehlerberichte

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 2793 C++98 eine extern-Deklaration in einem Block-Geltungsbereich könnte
mit einer anderen Deklaration im Eltern-Geltungsbereich kollidieren
verboten

[bearbeiten] Referenzen

  • C++23 Standard (ISO/IEC 14882:2024)
  • 6.4 Scope [basic.scope]
  • C++20 Standard (ISO/IEC 14882:2020)
  • 6.4 Scope [basic.scope]
  • C++17 Standard (ISO/IEC 14882:2017)
  • 6.3 Scope [basic.scope]
  • C++14 Standard (ISO/IEC 14882:2014)
  • 3.3 Scope [basic.scope]
  • C++11 Standard (ISO/IEC 14882:2011)
  • 3.3 Scope [basic.scope]
  • C++98 Standard (ISO/IEC 14882:1998)
  • 3.3 Deklarationsbereiche und Geltungsbereiche [basic.scope]

[bearbeiten] Siehe auch

C-Dokumentation für Geltungsbereich