Namespaces
Variants

Scope

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

Jede Deklaration , die in einem C++-Programm erscheint, ist nur in einigen möglicherweise nicht zusammenhängenden Gültigkeitsbereichen  sichtbar.

Innerhalb eines Geltungsbereichs kann unqualified name lookup verwendet werden, um einen Namen mit seiner Deklaration zu verknüpfen.

Inhaltsverzeichnis

Allgemein

Jedes Programm hat einen global scope  , der enthält das gesamte Programm.

Jeder andere Gültigkeitsbereich S wird durch eines der folgenden Elemente eingeführt:

(seit C++26)

S erscheint immer in einem anderen Gültigkeitsbereich, der dadurch enthält S .

Ein enclosing scope an einem Programmpunkt ist jeder Gültigkeitsbereich, der ihn enthält; der kleinste solche Gültigkeitsbereich wird als immediate scope an diesem Punkt bezeichnet.

Ein Geltungsbereich interveniert zwischen einem Programmpunkt P und einem Geltungsbereich S (der P nicht enthält), wenn er S ist oder enthält, aber P nicht enthält.

Der parent scope eines beliebigen Scopes S , der kein template parameter scope ist, ist der kleinste Scope, der S enthält und kein template parameter scope ist.

Sofern nicht anders angegeben:

  • Eine Deklaration belegt den unmittelbaren Gültigkeitsbereich an ihrem Locus .
  • Der Zielgültigkeitsbereich einer Deklaration ist der Gültigkeitsbereich, den sie belegt.
  • Alle durch eine Deklaration (wieder)eingeführten Namen werden in ihrem Zielgültigkeitsbereich an sie gebunden .

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

//                globaler  Gültigkeitsbereich  Gültigkeitsbereich
//                Gültigkeitsbereich     S      T
int x;         //   ─┐                 // Programm-Punkt X
               //    │
{              //    │     ─┐
    {          //    │      │     ─┐
        int y; //    │      │      │   // Programm-Punkt Y
    }          //    │      │     ─┘
}              //   ─┘     ─┘

Im obigen Programm:

  • Der globale Gültigkeitsbereich, Gültigkeitsbereich S und Gültigkeitsbereich T enthalten den Programmpunkt Y .
  • Mit anderen Worten, diese drei Gültigkeitsbereiche sind alle umschließende Gültigkeitsbereiche am Programmpunkt Y .
  • Der globale Bereich enthält die Bereiche S und T , und Bereich S enthält Bereich T .
  • Daher ist der Geltungsbereich T der kleinste aller drei Geltungsbereiche, was bedeutet:
  • Der Geltungsbereich T ist der unmittelbare Geltungsbereich am Programmpunkt Y .
  • Die Deklaration der Variable y belegt den Geltungsbereich T an ihrem Ort.
  • Der Geltungsbereich T ist der Zielgeltungsbereich der Deklaration von y .
  • Die Variable y gehört zum Geltungsbereich T .
  • Der Geltungsbereich S ist der übergeordnete Geltungsbereich von T , und der globale Geltungsbereich ist der übergeordnete Geltungsbereich von S .
  • Geltungsbereich S greift zwischen Programmpunkt X und Geltungsbereich T ein.

Blockbereich

Jeder

führt einen block scope ein, der die Anweisung oder den Handler enthält.

Eine Variable, die zu einem Blockbereich gehört, ist eine Blockvariable  (auch bekannt als lokale Variable).

int i = 42;
int a[10];
for (int i = 0; i < 10; i++) // inner “i” bewohnt den Blockgültigkeitsbereich
    a[i] = i;                // eingeführt durch die for-Anweisung
int j = i; // j = 42

Wenn die Deklaration einen Blockbereich S bewohnt und eine Funktion deklariert oder den extern Spezifizierer verwendet , darf die Deklaration nicht an ein benanntes Modul  angehängt werden (seit C++20) , ihr Zielbereich ist ein größerer umschließender Bereich (der innerste umschließende Namensbereich), aber der Name wird in ihrem unmittelbaren Bereich S gebunden.

Wenn eine Deklaration die keine namensunabhängige Deklaration ist und (since C++26) einen Namen im Blockgültigkeitsbereich S bindet

(seit C++11)
  • ein Unterstatement einer Auswahl- oder Iterationsanweisung, das selbst keine Auswahl- oder Iterationsanweisung ist, oder
  • ein Handler eines Funktions try -Blocks

potenziell in Konflikt steht mit einer Deklaration, deren Zielbereich der übergeordnete Bereich von S ist, ist das Programm fehlerhaft.

if (int x = f())  // deklariert "x"
{ // der if-Block ist ein Unterstatement des if-Statements
    int x;        // Fehler: Neudeklaration von "x"
}
else
{ // der else-Block ist ebenfalls ein Unterstatement des if-Statements
    int x;        // Fehler: Neudeklaration von "x"
}
void g(int i)
{
    extern int i; // Fehler: Neudeklaration von "i"
}

Funktionsparameterbereich

Jede Parameterdeklaration P führt einen Funktionsparameterbereich ein, der P einschließt.

  • Wenn die Funktionsdeklaration eine Funktionsdefinition ist, erstreckt sich der eingeführte Geltungsbereich bis zum Ende der Funktionsdefinition.
  • Andernfalls (wenn die Funktionsdeklaration ein Funktionsprototyp ist), erstreckt sich der eingeführte Geltungsbereich bis zum Ende des Funktionsdeklarators.
  • In beiden Fällen umfasst der Geltungsbereich nicht den Locus der Funktionsdeklaration.
  • Wenn der deklarierte Parameter zur Parameterliste eines Lambda-Ausdrucks gehört, erstreckt sich der eingeführte Gültigkeitsbereich bis zum Ende von { body } .
(seit C++11)
  • Wenn der deklarierte Parameter zur Parameterliste einer Deduction Guide gehört, erstreckt sich der eingeführte Gültigkeitsbereich bis zum Ende dieser Deduction Guide.
(seit C++17)
  • Wenn der deklarierte Parameter zur Parameterliste eines requires -Ausdrucks gehört, erstreckt sich der eingeführte Gültigkeitsbereich bis zum Ende von { requirement-seq } .
(seit C++20)
int f(int n) // die Deklaration des Parameters "n"
{            // führt einen Funktionsparameter-Bereich ein
    /* ... */
}            // der Funktionsparameter-Bereich endet hier

Lambda-Bereich

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

Die captures mit Initialisierern eines Lambda-Ausdrucks E befinden sich im Lambda-Bereich, der durch E eingeführt wird.

auto lambda = [x = 1, y]() // dieser Lambda-Ausdruck führt einen Lambda-Bereich ein,
{                          // er ist der Zielbereich des Captures "x"
    /* ... */
};                         // der Lambda-Bereich endet vor dem Semikolon
(seit C++14)

Namespace-Bereich

Jede Namespace-Definition für einen Namespace N führt einen Namespace-Bereich S ein, der die Deklarationen für jede Namespace-Definition für N enthält.

Für jede Nicht-Freund-Neudeklaration oder Spezialisierung, deren Zielbereich S ist oder in S enthalten ist, werden die folgenden Teile ebenfalls in den Bereich S eingeschlossen:

  • Für eine Klasse (Template)-Neudeklaration oder Klassentemplate-Spezialisierung, den Teil nach ihrem class-head-name .
  • Für eine Enumeration -Neudeklaration, den Teil nach ihrem enum-head-name .
  • Für jede andere Neudeklaration oder Spezialisierung, den Teil nach dem unqualified-id oder qualified-id des Deklarators .

Der globale Gültigkeitsbereich ist der Namensraumgültigkeitsbereich des globalen Namensraums .

namespace V   // die Namespace-Definition von "V"
{             // führt einen Namespace-Bereich "S" ein
    // der erste Teil des Bereichs "S" beginnt hier
    void f();
    // der erste Teil des Bereichs "S" endet hier
}
void V::f()   // der Teil nach "f" ist ebenfalls Teil des Bereichs "S"
{
    void h(); // deklariert V::h
}             // der zweite Teil des Bereichs "S" endet hier

Klassenbereich

Jede Deklaration einer Klasse oder eines Klassentemplates C führt einen Klassenbereich S ein, der die Member-Spezifikation der Klassendefinition von C umfasst.

Für jede Nicht-Freund-Neudeklaration oder Spezialisierung, deren Zielbereich S ist oder in S enthalten ist, werden die folgenden Teile ebenfalls in den Bereich S eingeschlossen:

  • Für eine class (Template)-Neudeklaration oder Klassentemplate-Spezialisierung, den Teil nach ihrem class-head-name .
  • Für eine enumeration -Neudeklaration, den Teil nach ihrem enum-head-name .
  • Für jede andere Neudeklaration oder Spezialisierung, den Teil nach der unqualified-id oder qualified-id des declarator .
class C       // die Klassendefinition von "C"
{             // führt einen Klassenbereich "S" ein
    // der erste Teil des Bereichs "S" beginnt hier
    void f();
    // der erste Teil des Bereichs "S" endet hier
}
void C::f()   // der Teil nach "f" ist ebenfalls Teil des Bereichs "S"
{
    /* ... */
}             // der zweite Teil des Bereichs "S" endet hier

Aufzählungsbereich

Jede Deklaration einer Enumeration E führt einen Enumeration-Scope ein, der die Enumerator-Liste der nicht-opaken (seit C++11) Enumeration-Deklaration von E (falls vorhanden) enthält.

enum class E // die Enumerationsdeklaration von "E"
{            // führt einen Enumerationsbereich "S" ein
    // Bereich "S" beginnt hier
    e1, e2, e3
    // Bereich "S" endet hier
}

Templateparameter-Bereich

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

Jede Template-Deklaration D führt einen Template-Parameter-Bereich 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 Bereich wie D .

Nur Template-Parameter gehören zu einem Template-Parameter-Bereich, und nur Template-Parameter-Bereiche haben einen Template-Parameter-Bereich als übergeordneten Bereich.

// Die Klassentemplate-Deklaration von "X"
// führt einen Template-Parameterbereich "S1" ein
template
<
    // Bereich "S1" beginnt hier
    template // Der Template-Template-Parameter "T"
             // führt einen weiteren Template-Parameterbereich "S2" ein
    <
        typename T1
        typename T2
    > requires std::convertible_from<T1, T2> // Bereich "S2" endet hier
    class T,
    typename U
>
class X; // Bereich "S1" endet vor dem Semikolon
namespace N
{
    template <typename T>
    using A = struct X; // "X" befindet sich im selben Bereich wie die Template-
                        // Deklaration, nämlich im Bereich von "N"
}

Vertragsassertions-Bereich

Jede Contract-Assertion C führt einen Vertragsassertions-Bereich ein, der C einschließt.

Wenn eine Nachbedingungs-Assertion einen Bezeichner besitzt, der nicht namensunabhängig ist, und die Nachbedingungs-Assertion mit einer Funktion func assoziiert ist, potenziell kollidiert mit einer Deklaration D , deren Zielbereich einer der folgenden Bereiche ist, ist das Programm fehlerhaft:

  • Der Funktionsparameterbereich von func .
  • Wenn D mit einem Lambda-Ausdruck assoziiert ist, der nächstgelegene umschließende Lambda-Bereich der Vorbedingungs-Assertion.
(seit C++26)

Punkt der Deklaration

Im Allgemeinen ist ein Name nach dem locus seiner ersten Deklaration sichtbar, der wie folgt lokalisiert wird.

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

int x = 32; // äußeres x ist im Gültigkeitsbereich
{
    int x = x; // inneres x ist im Gültigkeitsbereich vor dem Initialisierer (= x)
               // dies initialisiert das innere x nicht mit dem Wert des äußeren x (32),
               // dies initialisiert das innere x mit seinem eigenen (undefinierten) Wert
}
std::function<int(int)> f = [&](int n){ return n > 1 ? n * f(n - 1) : n; };
// der Name der Funktion f ist im Lambda-Ausdruck im Gültigkeitsbereich und kann
// korrekt per Referenz erfasst werden, was eine rekursive Funktion ergibt
const int x = 2; // äußeres x ist im Gültigkeitsbereich
{
    int x[x] = {}; // inneres x ist im Gültigkeitsbereich vor dem Initialisierer (= {}),
                   // aber nach dem Deklarator (x[x])
                   // im Deklarator ist das äußere x weiterhin im Gültigkeitsbereich
                   // dies deklariert ein Array von 2 int
}

Der Ort einer Klasse oder Klassentemplate-Deklaration ist unmittelbar nach dem Bezeichner, der die Klasse benennt (oder der template-id , die die Template-Spezialisierung benennt) in ihrem class-head . Der Klassen- oder Klassentemplate-Name ist bereits im Gültigkeitsbereich in der Liste der Basisklassen.

struct S: std::enable_shared_from_this<S> {}; // S ist beim Doppelpunkt im Gültigkeitsbereich

Der Ort des enum-Spezifizierers oder der opaken Enum-Deklaration (seit C++11) ist unmittelbar nach dem Bezeichner, der die Aufzählung benennt.

enum E : int // E ist im Gültigkeitsbereich beim Doppelpunkt
{
    A = sizeof(E)
};

Der Ort einer Typalias- oder Aliastemplate Deklaration ist unmittelbar nach der Typ-ID, auf die sich der Alias bezieht.

using T = int; // äußeres T ist am Semikolon im Gültigkeitsbereich
{
    using T = T*; // inneres T ist am Semikolon im Gültigkeitsbereich,
                  // äußeres T ist vor dem Semikolon weiterhin im Gültigkeitsbereich
                  // gleichbedeutend mit T = int*
}

Der Geltungsbereich für einen Deklarator in einer using declaration , die keinen Konstruktor benennt, ist 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 ist im Gültigkeitsbereich am Komma
          Base<next>::value; // Derived::value ist 1
};

Der Ort eines Enumerators befindet sich unmittelbar nach seiner Definition (nicht vor dem Initialisierer wie bei Variablen).

const int x = 12;
{
    enum
    {
        x = x + 1, // Enumerator x ist im Gültigkeitsbereich bis zum Komma,
                   // äußeres x ist im Gültigkeitsbereich vor dem Komma,
                   // Enumerator x wird mit 13 initialisiert
        y = x + 1  // y wird mit 14 initialisiert
    };
}

Der Ort für einen injected-class-name ist unmittelbar nach der öffnenden Klammer seiner Klasse (oder Klassenvorlage) Definition.

template<typename T>
struct Array
//  : std::enable_shared_from_this<Array> // Fehler: der injizierte Klassenname ist nicht im Gültigkeitsbereich
    : std::enable_shared_from_this< Array<T> > // OK: der Template-Name Array ist im Gültigkeitsbereich
{ // der injizierte Klassenname Array ist nun im Gültigkeitsbereich wie ein öffentlicher Mitgliedsname
    Array* p; // Zeiger auf Array<T>
};

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

(since C++11)


Der Geltungsbereich einer structured binding declaration beginnt unmittelbar nach der identifier-list , aber structured binding Initialisierern ist es untersagt, auf einen der deklarierten Namen zu verweisen.

(since C++17)


Der Geltungsbereich der Variablen oder der strukturierten Bindungen (seit C++17) , die in der range-declaration einer Range- for -Schleife deklariert werden, beginnt unmittelbar nach dem range-expression .

std::vector<int> x;
for (auto x : x) // Vektor x ist im Geltungsbereich vor der schließenden Klammer,
                 // auto x ist im Geltungsbereich an der schließenden Klammer
{
    // das auto x ist im Geltungsbereich
}
(seit C++11)

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

typedef unsigned char T;
template<
    class T = T, // Template-Parameter T ist am Komma im Gültigkeitsbereich,
                 // Typdef-Name von unsigned char ist vor dem Komma im Gültigkeitsbereich
    T // Template-Parameter T ist im Gültigkeitsbereich
    N = 0
>
struct A
{
};

Der Ort einer Nachbedingungsassertion mit einem Bezeichner ist unmittelbar nach ihrem : .

(since C++26)


Der Geltungsbereich einer Concept-Definition beginnt unmittelbar nach dem Concept-Namen, jedoch ist es Concept-Definitionen untersagt, auf den deklarierten Concept-Namen zu verweisen.

(since C++20)

Der Ort einer benannten Namespace-Definition ist unmittelbar nach dem Namespace-Namen.

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 2793 C++98 eine extern Deklaration im Blockbereich konnte
mit einer anderen Deklaration im übergeordneten Bereich in Konflikt stehen
verboten

Referenzen

  • C++23-Standard (ISO/IEC 14882:2024):
  • 6.4 Gültigkeitsbereich [basic.scope]
  • C++20-Standard (ISO/IEC 14882:2020):
  • 6.4 Gültigkeitsbereich [basic.scope]
  • C++17-Standard (ISO/IEC 14882:2017):
  • 6.3 Gültigkeitsbereich [basic.scope]
  • C++14-Standard (ISO/IEC 14882:2014):
  • 3.3 Gültigkeitsbereich [basic.scope]
  • C++11 Standard (ISO/IEC 14882:2011):
  • 3.3 Gültigkeitsbereich [basic.scope]
  • C++98-Standard (ISO/IEC 14882:1998):
  • 3.3 Deklarative Bereiche und Gültigkeitsbereiche [basic.scope]

Siehe auch