Each
that appears in a C++ program is only visible in some possibly discontiguous scopes .
Within a scope,
can be used to associate a name with its declaration.
General
Each program has a global scope , which contains the entire program.
Every other scope S is introduced by one of the following:
a
a parameter in
a
a
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
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
.
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 Tintx;// ─┐ // program point X// │{// │ ─┐{// │ │ ─┐inty;// │ │ │ // 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.
Block scope
Each
(
,
),
(
,
(since C++11),
,
),
, or
that is not the compound-statement of a handler
introduces a block scope that includes the statement or handler.
A variable that belongs to a block scope is a block variable .
inti=42;inta[10];for(inti=0;i<10;i++)// inner “i” inhabits the block scopea[i]=i;// introduced by the for-statementintj=i;// j = 42If 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
and(since C++26) that binds a name in the block scope S of
the compound-statement of a
or
,
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
with a declaration whose target scope is the parent scope of S, the program is ill-formed.
if(intx=f())// declares “x”{// the if-block is a substatement of the if-statementintx;// error: redeclaration of “x”}else{// the else-block is also a substatement of the if-statementintx;// error: redeclaration of “x”}voidg(inti){externinti;// error: redeclaration of “i”}Function parameter scope
Each
P introduces a function parameter scope that includes P.
If the declared parameter is of the parameter list of a
:
If the function declaration is a
, 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
of the function declaration.
If the declared parameter is of the parameter list of a
, the scope introduced is extended to the end of {body}.
(since C++11)If the declared parameter is of the parameter list of a
, 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
, the scope introduced is extended to the end of {requirement-seq}.
(since C++20)intf(intn)// the declaration of the parameter “n”{// introduces a function parameter scope/* ... */}// the function parameter scope ends hereLambda scope
Each
introduces a lambda scope that starts immediately after [captures] and extends to the end of {body}.
The
with initializers of a lambda expression E inhabit the lambda scope introduced by E.
autolambda=[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)Namespace scope
Every
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
(template) redeclaration or class template specialization, the portion after its class-head-name.
For a
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
.
The
is the namespace scope of the
.
namespaceV// the namespace definition of “V”{// introduces a namespace scope “S”// the first part of scope “S” begins herevoidf();// the first part of scope “S” ends here}voidV::f()// the portion after “f” is also a part of scope “S”{voidh();// declares V::h}// the second part of scope “S” ends hereClass scope
Each declaration of a class or class template C introduces a class scopeS that includes the member-specification of the
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
(template) redeclaration or class template specialization, the portion after its class-head-name.
For a
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
.
classC// the class definition of “C”{// introduces a class scope “S”// the first part of scope “S” begins herevoidf();// the first part of scope “S” ends here}voidC::f()// the portion after “f” is also a part of scope “S”{/* ... */}// the second part of scope “S” ends hereEnumeration scope
Each declaration of an enumeration E introduces an enumeration scope that includes the enumerator-list of the non-opaque(since C++11)
of E (if present).
enumclassE// the enumeration declaration of “E”{// introduces an enumeration scope “S”// scope “S” begins heree1,e2,e3// scope “S” ends here}Template parameter scope
Each
introduces a template parameter scope that includes the entire template parameter list and the
(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”<typenameT1typenameT2>requiresstd::convertible_from<T1,T2>// scope “S2” ends hereclassT,typenameU>classX;// scope “S1” ends before the semicolonnamespaceN{template<typenameT>usingA=structX;// “X” inhabits the same scope as template// declaration, namely the scope of “N”}Contract-assertion scope
Each
C introduces a contract-assertion scope that includes C.
If a
has an identifier which is not
, and the postcondition assertion is associated with a function func
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
, the nearest enclosing lambda scope of the precondition assertion.
(since C++26)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
and before its initializer, if any.
intx=32;// outer x is in scope{intx=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=[&](intn){returnn>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 functionconstintx=2;// outer x is in scope{intx[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
that names the template specialization) in its
. The class or class template name is already in scope in the list of base classes.
structS:std::enable_shared_from_this<S>{};// S is in scope at the colonThe locus of
or opaque enum declaration(since C++11) is immediately after the identifier that names the enumeration.
enumE:int// E is in scope at the colon{A=sizeof(E)};The locus of a
declaration is immediately after the type-id to which the alias refers.
usingT=int;// outer T is in scope at the semicolon{usingT=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
that does not name a constructor is immediately after the declarator.
template<intN>classBase{protected:staticconstintnext=N+1;staticconstintvalue=N;};structDerived:Base<0>,Base<1>,Base<2>{usingBase<0>::next,// next is in scope at the commaBase<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).
constintx=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 13y=x+1// y is initialized to 14};}The locus for an
is immediately following the opening brace of its class (or class template) definition.
template<typenameT>structArray// : 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 nameArray*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 item-declaration of a
is immediately after the range-initializer.
The locus of the variable or the structured bindings declared in the item-declaration of a
is immediately after the expansion-initializer.
(since C++26)std::vector<int>x;for(autox: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
is immediately after its complete template parameter (including the optional default argument).
typedefunsignedcharT;template<classT=T,// template parameter T is in scope at the comma,// typedef name of unsigned char is in scope before the commaT// template parameter T is in scopeN=0>structA{};The locus of a
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
is immediately after the namespace name.
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR Applied to Behavior as published Correct behavior
C++98 an extern declaration in a block scope could
conflict with another declaration in the parent scope prohibited 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]
See also