Namespaces
Variants
Actions

Scope

From cppreference.com
< cpp‎ | language
 
 
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
 
 

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:

(since C++26)

S always appear in another scope, which thereby containsS.

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:

  • A declaration inhabits the immediate scope at its locus.
  • A declaration’s target scope is the scope it inhabits.
  • Any names (re)introduced by a declaration are bound to it in its target scope.

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

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

In the program above:

  • The global scope, scope S and scope T contains program point Y.
  • In other words, these three scopes are all enclosing scopes at program point Y.
  • The global scope contains scopes S and T, and scope S contains scope T.
  • Therefore, scope T is the smallest scope among all three, which means:
  • Scope T is the immediate scope at program point Y.
  • The declaration of the variable y inhabits scope T at its locus.
  • Scope T is the target scope of the declaration of y.
  • The variable y belongs to scope T.
  • Scope S is the parent scope of scope T, and the global scope is the parent scope of scope S.
  • Scope S intervenes between program point X and scope T.

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

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

(since C++11)
  • a substatement of a selection or iteration statement that is not itself a selection or iteration statement, or
  • a handler of a function try block

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-statementint x;// error: redeclaration of “x”}else{// the else-block is also a substatement of the if-statementint x;// error: redeclaration of “x”}   void g(int i){externint i;// error: redeclaration of “i”}

[edit]Function parameter scope

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

  • If the function declaration is a function definition, the scope introduced is extended to the end of the function definition.
  • Otherwise (the function declaration is a function prototype), the scope introduced is extended to the end of the function declarator.
  • In both cases, the scope does not include the locus of the function declaration.
  • 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 scopeS 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:

  • For a class (template) redeclaration or class template specialization, the portion after its class-head-name.
  • For a enumeration redeclaration, the portion after its enum-head-name.
  • For any other redeclaration or specialization, the portion after the unqualified-id or qualified-id of the declarator.

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 herevoid 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 scopeS 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:

  • For a class (template) redeclaration or class template specialization, the portion after its class-head-name.
  • For a enumeration redeclaration, the portion after its enum-head-name.
  • For any other redeclaration or specialization, the portion after the unqualified-id or qualified-id of the declarator.
class C // the class definition of “C”{// introduces a class scope “S”// the first part of scope “S” begins herevoid 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).

enumclass 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 scopeS 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 heretemplate// the template template parameter “T”// introduces another template parameter scope “S2”<typename T1 typename T2 > requires std::convertible_from<T1, T2>// scope “S2” ends hereclass 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”}

Contract-assertion scope

Each contract assertionC 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 funcpotentially 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
constint 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.

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

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<int N>class Base {protected:staticconstint next = N +1;staticconstint 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};

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

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

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

typedefunsignedchar 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 postcondition assertion with an identifier is immediately after its :.

(since C++26)


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 2793C++98 an extern declaration in a block scope could
conflict with another declaration in the parent scope
prohibited

[edit]References

  • 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 Declarative regions and scopes [basic.scope]

[edit]See also

C documentation for Scope
close