3 Basic concepts [basic]

3.3 Scope [basic.scope]

3.3.1 Declarative regions and scopes [basic.scope.declarative]

Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity. In general, each particular name is valid only within some possibly discontiguous portion of program text called its scope. To determine the scope of a declaration, it is sometimes convenient to refer to the potential scope of a declaration. The scope of a declaration is the same as its potential scope unless the potential scope contains another declaration of the same name. In that case, the potential scope of the declaration in the inner (contained) declarative region is excluded from the scope of the declaration in the outer (containing) declarative region.

Example: in

int j = 24;
int main() {
  int i = j, j;
  j = 42;
}

the identifier j is declared twice as a name (and used twice). The declarative region of the first j includes the entire example. The potential scope of the first j begins immediately after that j and extends to the end of the program, but its (actual) scope excludes the text between the , and the }. The declarative region of the second declaration of j (the j immediately before the semicolon) includes all the text between { and }, but its potential scope excludes the declaration of i. The scope of the second declaration of j is the same as its potential scope.  — end example ]

The names declared by a declaration are introduced into the scope in which the declaration occurs, except that the presence of a friend specifier ([class.friend]), certain uses of the elaborated-type-specifier ([dcl.type.elab]), and using-directives ([namespace.udir]) alter this general behavior.

Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,

  • they shall all refer to the same entity, or all refer to functions and function templates; or

  • exactly one declaration shall declare a class name or enumeration name that is not a typedef name and the other declarations shall all refer to the same variable, non-static data member, or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden ([basic.scope.hiding]). [ Note: A namespace name or a class template name must be unique in its declarative region ([namespace.alias], Clause [temp]).  — end note ]

Note: These restrictions apply to the declarative region into which a name is introduced, which is not necessarily the same as the region in which the declaration occurs. In particular, elaborated-type-specifiers ([dcl.type.elab]) and friend declarations ([class.friend]) may introduce a (possibly not visible) name into an enclosing namespace; these restrictions apply to that region. Local extern declarations ([basic.link]) may introduce a name into the declarative region where the declaration appears and also introduce a (possibly not visible) name into an enclosing namespace; these restrictions apply to both regions.  — end note ]

Note: The name lookup rules are summarized in [basic.lookup].  — end note ]

3.3.2 Point of declaration [basic.scope.pdecl]

The point of declaration for a name is immediately after its complete declarator (Clause [dcl.decl]) and before its initializer (if any), except as noted below. [ Example:

unsigned char x = 12;{ unsigned char x = x; }

Here the second x is initialized with its own (indeterminate) value.  — end example ]

Note: a name from an outer scope remains visible up to the point of declaration of the name that hides it. [ Example:

const int  i = 2;{ int  i[i]; }

declares a block-scope array of two integers.  — end example ]  — end note ]

The point of declaration for a class or class template first declared by a class-specifier is immediately after the identifier or simple-template-id (if any) in its class-head (Clause [class]). The point of declaration for an enumeration is immediately after the identifier (if any) in either its enum-specifier ([dcl.enum]) or its first opaque-enum-declaration ([dcl.enum]), whichever comes first. The point of declaration of an alias or alias template immediately follows the type-id to which the alias refers.

The point of declaration of a using-declarator that does not name a constructor is immediately after the using-declarator ([namespace.udecl]).

The point of declaration for an enumerator is immediately after its enumerator-definition. [ Example:

const int x = 12;{ enum { x = x }; }

Here, the enumerator x is initialized with the value of the constant x, namely 12.  — end example ]

After the point of declaration of a class member, the member name can be looked up in the scope of its class. [ Note: this is true even if the class is an incomplete class. For example,

struct X {
  enum E { z = 16 };
  int b[X::z];      // OK
};

 — end note ]

The point of declaration of a class first declared in an elaborated-type-specifier is as follows:

The point of declaration for an injected-class-name (Clause [class]) is immediately following the opening brace of the class definition.

The point of declaration for a function-local predefined variable ([dcl.fct.def]) is immediately before the function-body of a function definition.

The point of declaration for a template parameter is immediately after its complete template-parameter. [ Example:

typedef unsigned char T;
template<class T
  = T     // lookup finds the typedef name of unsigned char
  , T     // lookup finds the template parameter
    N = 0> struct A { };

 — end example ]

Note: Friend declarations refer to functions or classes that are members of the nearest enclosing namespace, but they do not introduce new names into that namespace ([namespace.memdef]). Function declarations at block scope and variable declarations with the extern specifier at block scope refer to declarations that are members of an enclosing namespace, but they do not introduce new names into that scope.  — end note ]

Note: For point of instantiation of a template, see [temp.point]. — end note ]

3.3.3 Block scope [basic.scope.block]

A name declared in a block ([stmt.block]) is local to that block; it has block scope. Its potential scope begins at its point of declaration ([basic.scope.pdecl]) and ends at the end of its block. A variable declared at block scope is a local variable.

The potential scope of a function parameter name (including one appearing in a lambda-declarator) or of a function-local predefined variable in a function definition ([dcl.fct.def]) begins at its point of declaration. If the function has a function-try-block the potential scope of a parameter or of a function-local predefined variable ends at the end of the last associated handler, otherwise it ends at the end of the outermost block of the function definition. A parameter name shall not be redeclared in the outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block.

The name declared in an exception-declaration is local to the handler and shall not be redeclared in the outermost block of the handler.

Names declared in the init-statement, the for-range-declaration, and in the condition of if, while, for, and switch statements are local to the if, while, for, or switch statement (including the controlled statement), and shall not be redeclared in a subsequent condition of that statement nor in the outermost block (or, for the if statement, any of the outermost blocks) of the controlled statement; see [stmt.select].

3.3.4 Function prototype scope [basic.scope.proto]

In a function declaration, or in any function declarator except the declarator of a function definition ([dcl.fct.def]), names of parameters (if supplied) have function prototype scope, which terminates at the end of the nearest enclosing function declarator.

3.3.5 Function scope [basic.funscope]

Labels ([stmt.label]) have function scope and may be used anywhere in the function in which they are declared. Only labels have function scope.

3.3.6 Namespace scope [basic.scope.namespace]

The declarative region of a namespace-definition is its namespace-body. Entities declared in a namespace-body are said to be members of the namespace, and names introduced by these declarations into the declarative region of the namespace are said to be member names of the namespace. A namespace member name has namespace scope. Its potential scope includes its namespace from the name's point of declaration ([basic.scope.pdecl]) onwards; and for each using-directive ([namespace.udir]) that nominates the member's namespace, the member's potential scope includes that portion of the potential scope of the using-directive that follows the member's point of declaration. [ Example:

namespace N {
  int i;
  int g(int a) { return a; }
  int j();
  void q();
}
namespace { int l=1; }
// the potential scope of l is from its point of declaration
// to the end of the translation unit

namespace N {
  int g(char a) {   // overloads N::g(int)
    return l+a;     // l is from unnamed namespace
  }

  int i;            // error: duplicate definition
  int j();          // OK: duplicate function declaration

  int j() {         // OK: definition of N::j()
    return g(i);    // calls N::g(int)
  }
  int q();          // error: different return type
}

 — end example ]

A namespace member can also be referred to after the :: scope resolution operator ([expr.prim]) applied to the name of its namespace or the name of a namespace which nominates the member's namespace in a using-directive; see [namespace.qual].

The outermost declarative region of a translation unit is also a namespace, called the global namespace. A name declared in the global namespace has global namespace scope (also called global scope). The potential scope of such a name begins at its point of declaration ([basic.scope.pdecl]) and ends at the end of the translation unit that is its declarative region. A name with global namespace scope is said to be a global name.

3.3.7 Class scope [basic.scope.class]

The potential scope of a name declared in a class consists not only of the declarative region following the name's point of declaration, but also of all function bodies, default arguments, noexcept-specifiers, and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes).

A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.

A name declared within a member function hides a declaration of the same name whose scope extends to or past the end of the member function's class.

The potential scope of a declaration that extends to or past the end of a class definition also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class (this includes static data member definitions, nested class definitions, and member function definitions, including the member function body and any portion of the declarator part of such definitions which follows the declarator-id, including a parameter-declaration-clause and any default arguments ([dcl.fct.default])).

Example:

typedef int  c;
enum { i = 1 };

class X {
  char  v[i];                       // error: i refers to ::i
                                    // but when reevaluated is X::i
  int  f() { return sizeof(c); }    // OK: X::c
  char  c;
  enum { i = 2 };
};

typedef char*  T;
struct Y {
  T  a;                             // error: T refers to ::T
                                    // but when reevaluated is Y::T
  typedef long  T;
  T  b;
};

typedef int I;
class D {
  typedef I I;                      // error, even though no reordering involved
};

 — end example ]

The name of a class member shall only be used as follows:

  • in the scope of its class (as described above) or a class derived (Clause [class.derived]) from its class,

  • after the . operator applied to an expression of the type of its class ([expr.ref]) or a class derived from its class,

  • after the -> operator applied to a pointer to an object of its class ([expr.ref]) or a class derived from its class,

  • after the :: scope resolution operator ([expr.prim]) applied to the name of its class or a class derived from its class.

3.3.8 Enumeration scope [basic.scope.enum]

The name of a scoped enumerator ([dcl.enum]) has enumeration scope. Its potential scope begins at its point of declaration and terminates at the end of the enum-specifier.

3.3.9 Template parameter scope [basic.scope.temp]

The declarative region of the name of a template parameter of a template template-parameter is the smallest template-parameter-list in which the name was introduced.

The declarative region of the name of a template parameter of a template is the smallest template-declaration in which the name was introduced. Only template parameter names belong to this declarative region; any other kind of name introduced by the declaration of a template-declaration is instead introduced into the same declarative region where it would be introduced as a result of a non-template declaration of the same name. [ Example:

namespace N {
  template<class T> struct A { };               // #1
  template<class U> void f(U) { }               // #2
  struct B {
    template<class V> friend int g(struct C*);  // #3
  };
}

The declarative regions of T, U and V are the template-declarations on lines #1, #2 and #3, respectively. But the names A, f, g and C all belong to the same declarative region — namely, the namespace-body of N. (g is still considered to belong to this declarative region in spite of its being hidden during qualified and unqualified name lookup.)  — end example ]

The potential scope of a template parameter name begins at its point of declaration ([basic.scope.pdecl]) and ends at the end of its declarative region. [ Note: This implies that a template-parameter can be used in the declaration of subsequent template-parameters and their default arguments but cannot be used in preceding template-parameters or their default arguments. For example,

template<class T, T* p, class U = T> class X { /* ... */ };
template<class T> void f(T* p = new T);

This also implies that a template-parameter can be used in the specification of base classes. For example,

template<class T> class X : public Array<T> { /* ... */ };
template<class T> class Y : public T { /* ... */ };

The use of a template parameter as a base class implies that a class used as a template argument must be defined and not just declared when the class template is instantiated.  — end note ]

The declarative region of the name of a template parameter is nested within the immediately-enclosing declarative region. [ Note: As a result, a template-parameter hides any entity with the same name in an enclosing scope ([basic.scope.hiding]). [ Example:

typedef int N;
template<N X, typename N, template<N Y> class T> struct A;

Here, X is a non-type template parameter of type int and Y is a non-type template parameter of the same type as the second template parameter of A.  — end example ] — end note ]

Note: Because the name of a template parameter cannot be redeclared within its potential scope ([temp.local]), a template parameter's scope is often its potential scope. However, it is still possible for a template parameter name to be hidden; see [temp.local].  — end note ]

3.3.10 Name hiding [basic.scope.hiding]

A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class ([class.member.lookup]).

A class name ([class.name]) or enumeration name ([dcl.enum]) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

In a member function definition, the declaration of a name at block scope hides the declaration of a member of the class with the same name; see [basic.scope.class]. The declaration of a member in a derived class (Clause [class.derived]) hides the declaration of a member of a base class of the same name; see [class.member.lookup].

During the lookup of a name qualified by a namespace name, declarations that would otherwise be made visible by a using-directive can be hidden by declarations with the same name in the namespace containing the using-directive; see [namespace.qual].

If a name is in scope and is not hidden it is said to be visible.