Namespaces
Variants
Views
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 declaration
inline specifier
Exception specifications (until C++20)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
decltype (C++11)
auto (C++11)
alignas (C++11)
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
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
 
 

Each name that appears in a C++ program is only valid in some possibly discontiguous portion of the source code called its scope.

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

Contents

[edit] Block scope

The potential scope of a variable introduced by a declaration in a block (compound statement) begins at the point of declaration and ends at the end of the block. Actual scope is the same as potential scope unless there is a nested block with a declaration that introduces identical name (in which case, the entire potential scope of the nested declaration is excluded from the scope of the outer declaration)

int main()
{
    int a = 0; // scope of the first 'a' begins
    ++a; // the name 'a' is in scope and refers to the first 'a'
    {
        int a = 1; // scope of the second 'a' begins
                   // scope of the first 'a' is interrupted
        a = 42;    // 'a' is in scope and refers to the second 'a'                 
    } // block ends, scope of the second 'a' ends
      //             scope of the first 'a' resumes
} // block ends, scope of the first 'a' ends
int b = a; // Error: name 'a' is not in scope

The potential scope of a name declared in an exception handler begins at the point of declaration and ends when the exception handler ends, and is not in scope in another exception handler or in the enclosing block.

try {   
    f();
} catch(const std::runtime_error& re) { // scope of re begins
    int n = 1; // scope of n begins
    std::cout << re.what(); // re is in scope
} // scope of re ends, scope of n ends
 catch(std::exception& e) {
    std::cout << re.what(); // error: re is not in scope
    ++n; // error: n is not in scope
}

The potential scope of a name declared in the init-statement of the for loop, in the condition of a for loop, in the range_declaration of a range for loop, in the init-statement of the if statement or switch statement (since C++17), in the condition of the if statement, while loop, or switch statement begins at the point of declaration and ends at the end of the controlled statement.

Base* bp = new Derived;
if(Derived* dp = dynamic_cast<Derived*>(bp))
{
    dp->f(); // dp is in scope
} // scope of dp ends
 
for(int n = 0; // scope of n begins
    n < 10;    // n is in scope
    ++n)       // n is in scope
{
    std::cout << n << ' '; // n is in scope
} // scope of n ends

[edit] Function parameter scope

The potential scope of a function parameter (including parameters of a lambda expression) or of a function-local predefined variable begins at its point of declaration.

  • If the nearest enclosing function declarator is not the declarator of a function definition, its potential scope ends at the end of that function declarator.
  • Otherwise, its potential scope ends at the end of the last exception handler of the function-try-block, or at the end of the function body if a function try block was not used.
const int n = 3;
 
int f1(int n,     // scope of global 'n' interrupted,
                  // scope of the parameter 'n' begins
       int y = n); // error: default argument references a parameter
 
int (*(*f2)(int n))[n]; // OK: the scope of the function parameter 'n'
                        // ends at the end of its function declarator
                        // in the array declarator, global n is in scope
// (this declares a pointer to function returning a pointer to an array of 3 int
 
// by contrast
auto (*f3)(int n)->int (*)[n]; // error: parameter 'n' as array bound
 
 
int f(int n = 2)  // scope of 'n' begins
try // function try block
{         // the body of the function begins
   ++n;   // 'n' is in scope and refers to the function parameter
   {
      int n = 2; // scope of the local variable 'n' begins
                 // scope of function parameter 'n' interrupted 
      ++n; // 'n' refers to the local variable in this block
    }            // scope of the local variable 'n' ends
                 // scope of function parameter 'n' resumes
} catch(...) {
   ++n; // n is in scope and refers to the function parameter
   throw;
} // last exception handler ends, scope of function parameter 'n' ends
int a = n; // OK: global 'n' is in scope

[edit] Namespace scope

A name declared in a namespace becomes visible at the locus of its first declaration and is in scope in all namespace definitions for the same namespace that follow, plus, for any using-directive that introduced this name or its entire namespace into another scope, the rest of that scope.

The top-level scope of a translation unit ("file scope" or "global scope") is also a namespace and is properly called "global namespace scope". Any name declared in the global namespace scope becomes visible at the locus of its first declaration and remains in scope until the end of the translation unit.

A name declared in an unnamed namespace or in an inline namespace is visible in the enclosing namespace.

namespace N { // scope of N begins (as a member of global namespace)
    int i; // scope of i begins
    int g(int a) { return a; } // scope of g begins
    int j(); // scope of j begins
    void q(); // scope of q begins
    namespace {
        int x; // scope of x begins
    } // scope of x does not end
    inline namespace inl { // scope of inl begins
      int y; // scope of y begins
    } // scope of y does not end
} // scope of i,g,j,q,inl,x,y interrupted
 
namespace {
    int l=1; // scope of l begins
} // scope of l does not end (it's a member of unnamed namespace)
 
namespace N { // scope of i,g,j,q,inl,x,y continues
    int g(char a) {  // overloads N::g(int)
        return l+a;  // l from unnamed namespace is in scope
    }
    int i; // error: duplicate definition (i is already in scope)
    int j(); // OK: repeat function declaration is allowed
    int j() { // OK: definition of the earlier-declared N::j()
        return g(i); // calls N::g(int)
    }
    int q(); // error: q is already in scope with different return type
} // scope of i,g,j,q,inl,x,y interrupted
 
int main() {
    using namespace N; // scope of i,g,j,q,inl,x,y resumes
    i = 1; // N::i is in scope
    x = 1; // N::(anonymous)::x is in scope
    y = 1; // N::inl::y is in scope
    inl::y = 2; // N::inl is also in scope
} // scope of i,g,j,q,inl,x,y interrupted

The name may also be visible in translation units that have imported the current translation unit.

(since C++20)

[edit] Class scope

The potential scope of a name declared in a class begins at the point of declaration and includes the rest of the class body and all function bodies (even if defined outside the class definition or before the declaration of the name), default arguments, exception specifications, in-class brace-or-equal initializers, and all these things in nested classes, recursively.

class X {
    int f(int a = n) { // X::n is in scope inside default parameter
         return a*n;   // X::n is in scope inside function body
    }
    using r = int;
    r g();
    int i = n*2;   // X::n is in scope inside initializer
 
//  int x[n];      // Error: n is not in scope in class body
    static const int n = 1;
    int x[n];      // OK: n is now in scope in class body
};
 
//r X::g() {       // Error: r is not in scope outside of out-of-class member function body
auto X::g()->r {   // OK: trailing return type X::r is in scope
    return n;      // X::n is in scope in out-of-class member function body
}

If a name is used in a class body before it is declared, and another declaration for that name is in scope, the program is ill-formed, no diagnostic required.

typedef int c; // ::c
enum { i = 1 }; // ::i
class X {
    char v[i]; // Error: at this point, i refers to ::i
               // but there is also X::i
    int f() {
         return sizeof(c); // OK: X::c, not ::c is in scope inside a member function
    }
    char c; // X::c
    enum { i = 2 }; // X::i
};
 
typedef char* T;
struct Y {
    T a; // Error: at this point, T refers to ::T
         // but there is also Y::T
    typedef long T;
    T b;
};

Names of class members can be used in the following contexts:

  • in its own class scope or in the class scope of a derived class
  • after the . operator applied to an expression of the type of its class or a class derived from it
  • after the -> operator applied to an expression of the type of pointer to its class or pointers to a class derived from it
  • after the :: operator applied to the name of its class or the name of a class derived from it

[edit] Enumeration scope

The name of an enumerator introduced in a scoped enumeration begins at the point of declaration and ends at the end of the enum specifier (in contrast, unscoped enumerators are in scope after the end of the enum specifier)

enum e1_t { // unscoped enumeration
  A,
  B = A*2
}; // scope of A and B does not end
 
enum class e2_t { // scoped enumeration
    SA,
    SB = SA*2 // SA is in scope
}; // scope of SA and SB ends
 
e1_t e1 = B; // OK, B is in scope
// e2_t e2 = SB; // Error: SB is not in scope
e2_t e2 = e2_t::SB; // OK

[edit] Template parameter scope

The potential scope of a template parameter name begins immediately at the point of declaration and continues to the end of the smallest template declaration in which it was introduced. In particular, a template parameter can be used in the declarations of subsequent template parameters and in the specifications of base classes, but can't be used in the declarations of the preceding template parameters.

template< typename T, // scope of T begins
          T* p,       // T can be used for a non-type parameter
          class U = T // T can be used for a default type
        >
class X : public Array<T> // T can be used in base class name
{
   // T can be used inside the body as well
}; // scopes of T and U end, scope of X continues

The potential scope of the name of the parameter of a template template parameter is the smallest template parameter list in which that name appears

template< template< // template template parameter
                    typename Y,     // scope of Y begins
                    typename G = Y // Y is in scope
                  > // scopes of Y and G end
          class T,
//          typename U = Y // Error: Y is not in scope
          typename U
        >
class X
{
}; // scopes of T and U end

Similar to other nested scopes, the name of a template parameter hides the same name from the outer scope for the duration of its own:

typedef int N;
template< N X, // non-type parameter of type int
          typename N, // scope of this N begins, scope of ::N interrupted
          template<N Y> class T // N here is the template parameter, not int
         > struct A;

[edit] Point of declaration

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

For variables and other names introduced by simple declarations, the locus is immediately after that name's declarator and before its initializer, if any:

unsigned char x = 32; // the first 'x' becomes visible
{
    unsigned char x = x; // the second 'x' becomes visible before the initializer (= x)
                         // this does not initialize the second 'x' with the value 32, 
                         // this initializes the second '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 within the lambda, and can
           // be correctly captured by reference, giving a recursive function
const int x = 2; // the first 'x' becomes visible
{
    int x[x] = {}; // the second x becomes visible before the initializer (= {})
                   // but after the declarator (x[x]). Within the declarator, the 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) appears in its class-head. The class or class template name is already in scope in the list of the base classes:

// the name 'S' is in scope immediately after it appears, 
// so it can be used in the list of base classes
struct S: std::enable_shared_from_this<S> 
{
};

The locus of enum specifier or opaque enum declaration is immediately after the identifier that names the enumeration:

enum E : int { // E is already in scope
    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; // point of declaration of T is at the semicolon
{
    using T = T*;   // 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:
    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 now in scope
          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):

const int x = 12;
{
    enum { x = x + 1, // point of declaration is at the comma, x is initialized to 13
           y = x + 1  // the enumerator x is now in scope, 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 introduced.

(since C++17)

The locus for the variable or the structured bindings (since C++17) declared in the range_declaration of a range-based for statement is immediately after the range_expression:

std::vector<int> x;
 
for (auto x : x) { // OK: the second x refers the std::vector<int>
// x refers the loop variable in the body of the loop
}
(since C++11)

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

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

The locus of a concept definition is immediately after the concept name, but concept definitions are prohibited from referring to the concept name being introduced.

(since C++20)

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


[edit] References

  • 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