Scope - cppreference.com (original) (raw)

Each declaration that appears in a C++ program is only visible in some possibly discontiguous scopes .

Within a scope, unqualified name lookup can be used to associate a name with its declaration.

Contents

[edit] General

Each program has a global scope , which contains the entire program.

Every other scope S is introduced by one of the following:

S always appear in another scope, which thereby contains S.

An enclosing scope at a program point is any scope that contains it; the smallest such scope is said to be the immediate scope at that point.

A scope intervenes between a program point P and a scope S (that does not contain P) if it is or contains S but does not contain P.

The parent scope of any scope S that is not a template parameter scope is the smallest scope that contains S and is not a template parameter scope.

Unless otherwise specified:

An entity belongs to a scope S if S is the target scope of a declaration of the entity.

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

In the program above:

[edit] Block scope

Each

introduces a block scope that includes the statement or handler.

A variable that belongs to a block scope is a block variable (also known as local variable).

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

If the declaration inhabits a block scope S and declares a function or uses the extern specifier, the declaration shall not be attached to a named module (since C++20), its target scope is a larger enclosing scope (the innermost enclosing namespace scope), but the name is bound in their immediate scope S.

If a declaration that is not a name-independent declaration and(since C++26) that binds a name in the block scope S of

potentially conflicts with a declaration whose target scope is the parent scope of S, the program is ill-formed.

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

[edit] Function parameter scope

Each parameter declaration P introduces a function parameter scope that includes P.

If the declared parameter is of the parameter list of a lambda expression, the scope introduced is extended to the end of { body }. (since C++11)
If the declared parameter is of the parameter list of a deduction guide, the scope introduced is extended to the end of that deduction guide. (since C++17)
If the declared parameter is of the parameter list of a requires expression, the scope introduced is extended to the end of { requirement-seq }. (since C++20)

int f(int n) // the declaration of the parameter “n” { // introduces a function parameter scope /* ... */ } // the function parameter scope ends here

Lambda scope Each lambda expression introduces a lambda scope that starts immediately after [captures ] and extends to the end of { body }.The captures with initializers of a lambda expression E inhabit the lambda scope introduced by E. 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 (since C++14)

[edit] Namespace scope

Every namespace definition for a namespace N introduces a namespace scope S that includes the declarations for every namespace definition for N.

For each non-friend redeclaration or specialization whose target scope is S or is contained by S, the following portions are also included in scope S:

The global scope is the namespace scope of the global namespace.

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

[edit] Class scope

Each declaration of a class or class template C introduces a class scope S that includes the member-specification of the class definition of C.

For each non-friend redeclaration or specialization whose target scope is S or is contained by S, the following portions are also included in scope S:

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

[edit] Enumeration scope

Each declaration of an enumeration E introduces an enumeration scope that includes the enumerator-list of the non-opaque(since C++11) enumeration declaration of E (if present).

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

[edit] Template parameter scope

Each template template parameter introduces a template parameter scope that includes the entire template parameter list and the require clauses(since C++20) of that template template parameter.

Each template declaration D introduces a template parameter scope S that extends from the beginning of the template parameter list of D to the end of D. Any declaration outside the template parameter list that would inhabit S instead inhabits the same scope as D.

Only template parameters belong to a template parameter scope, and only template parameter scopes have a template parameter scope as a parent scope.

// 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 using A = struct X; // “X” inhabits the same scope as template // declaration, namely the scope of “N” }

Contract-assertion scope Each contract assertion C introduces a contract-assertion scope that includes C.If a postcondition assertion has an identifier which is not name-independent, and the postcondition assertion is associated with a function func potentially conflicts with a declaration D whose target scope is one of the following scopes, the program is ill-formed: The function parameter scope of func. If D is associated with a lambda expression, the nearest enclosing lambda scope of the precondition assertion. (since C++26)

[edit] Point of declaration

In general, a name is visible after the locus of its first declaration, which is located as follows.

The locus of a name declared in a simple declaration is immediately after that name's declarator and before its initializer, if any.

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 }

The locus of a class or class template declaration is immediately after the identifier that names the class (or the template-id that names the template specialization) in its class-head. The class or class template name is already in scope in the list of base classes.

The locus of enum specifier or opaque enum declaration(since C++11) is immediately after the identifier that names the enumeration.

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

The locus of a type alias or alias template declaration is immediately after the type-id to which the alias refers.

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

The locus for a declarator in a using declaration that does not name a constructor is immediately after the declarator.

template 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::value; // Derived::value is 1 };

The locus of an enumerator is immediately after its definition (not before the initializer as it is for variables).

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

The locus for an injected-class-name is immediately following the opening brace of its class (or class template) definition.

template struct Array //  : std::enable_shared_from_this // error: the injected class name is not in scope : std::enable_shared_from_this< Array > // 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 };

The locus of the implicit declaration for a function-local predefined variable __func__ is immediately before the function body of a function definition. (since C++11)
The locus of a structured binding declaration is immediately after the identifier-list, but structured binding initializers are prohibited from referring to any of the names being declared. (since C++17)
The locus of the variable or the structured bindings(since C++17) declared in the range-declaration of a range-for loop is immediately after the 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 } (since C++11)

The locus of a template parameter is immediately after its complete template parameter (including the optional default argument).

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 { };

The locus of a concept definition is immediately after the concept name, but concept definitions are prohibited from referring to the concept name being declared. (since C++20)

The locus of a named namespace definition is immediately after the namespace name.

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 2793 C++98 an extern declaration in a block scope couldconflict with another declaration in the parent scope prohibited

[edit] References

[edit] See also