Namespaces
Variants

Scope

From cppreference.net
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

Каждая декларация , появляющаяся в программе на C++, видима только в некоторых возможно несмежных областях видимости  .

В пределах области видимости, поиск неквалифицированного имени может использоваться для связывания имени с его объявлением.

Содержание

Общее

Каждая программа имеет глобальную область видимости  , которая содержит всю программу.

Каждая другая область видимости S вводится одним из следующих способов:

(since C++26)

S всегда появляется в другой области видимости, которая тем самым содержит S .

Охватывающая область видимости в точке программы — это любая область видимости, которая её содержит; наименьшая такая область называется непосредственной областью видимости в этой точке.

Область видимости вмешивается между точкой программы P и областью видимости S (которая не содержит P ), если она является или содержит S , но не содержит P .

Родительская область видимости любой области видимости S , которая не является областью видимости параметров шаблона , — это наименьшая область видимости, которая содержит S и не является областью видимости параметров шаблона.

Если не указано иное:

  • Объявление обитает в непосредственной области видимости в своём локусе .
  • Целевая область видимости объявления — это область видимости, в которой оно обитает.
  • Любые имена, (пере)вводимые объявлением, связываются с ним в его целевой области видимости.

Сущность принадлежит области видимости S если S является целевой областью видимости объявления этой сущности.

//                глобальная  область  область
//                область      S        T
int x;         //   ─┐                 // точка программы X
               //    │
{              //    │     ─┐
    {          //    │      │     ─┐
        int y; //    │      │      │   // точка программы Y
    }          //    │      │     ─┘
}              //   ─┘     ─┘

В приведенной выше программе:

  • Глобальная область видимости, область видимости S и область видимости T содержат точку программы Y .
  • Другими словами, все три области видимости являются охватывающими областями в точке программы Y .
  • Глобальная область содержит области S и T , причём область S содержит область T .
  • Следовательно, область видимости T является наименьшей из всех трёх, что означает:
  • Область видимости T является непосредственной областью видимости в точке программы Y .
  • Объявление переменной y располагается в области видимости T в своём локусе.
  • Область видимости T является целевой областью видимости для объявления y .
  • Переменная y принадлежит области видимости T .
  • Область видимости S является родительской областью видимости для области T , а глобальная область видимости является родительской областью для области S .
  • Область видимости S располагается между точкой программы X и областью видимости T .

Область видимости блока

Каждый

вводит область видимости блока , которая включает оператор или обработчик.

Переменная, принадлежащая области видимости блока, называется блочной переменной (также известной как локальная переменная).

int i = 42;
int a[10];
for (int i = 0; i < 10; i++) // внутренняя переменная «i» существует в области видимости блока
    a[i] = i;                // введённой оператором for
int j = i; // j = 42

Если объявление находится в области видимости блока S и объявляет функцию или использует спецификатор extern , объявление не должно быть прикреплено к именованному модулю  (начиная с C++20) , его целевая область видимости является более широкой охватывающей областью (самая внутренняя охватывающая область видимости пространства имён), но имя связывается в их непосредственной области видимости S .

Если объявление которое не является независимым от имени объявлением и (since C++26) связывает имя в области видимости блока S

(since C++11)
  • подоператор оператора выбора или цикла, который сам не является оператором выбора или цикла, или
  • обработчик блока функции try

потенциально конфликтует с объявлением, целевой областью видимости которого является родительская область видимости S , программа является некорректной.

if (int x = f())  // объявляет "x"
{ // if-блок является подоператором if-оператора
    int x;        // ошибка: переопределение "x"
}
else
{ // else-блок также является подоператором if-оператора
    int x;        // ошибка: переопределение "x"
}
void g(int i)
{
    extern int i; // ошибка: переопределение "i"
}

Область видимости параметров функции

Каждый parameter declaration P вводит function parameter scope , который включает P .

  • Если объявление функции является определением функции , введенная область видимости распространяется до конца определения функции.
  • В противном случае (объявление функции является прототипом функции), введенная область видимости распространяется до конца декларатора функции.
  • В обоих случаях область видимости не включает точку объявления функции.
  • Если объявленный параметр находится в списке параметров лямбда-выражения , введенная область видимости распространяется до конца { body } .
(начиная с C++11)
  • Если объявленный параметр находится в списке параметров руководства по выводу , введенная область видимости распространяется до конца этого руководства по выводу.
(начиная с C++17)
  • Если объявленный параметр находится в списке параметров requires выражения , введенная область видимости распространяется до конца { requirement-seq } .
(начиная с C++20)
int f(int n) // объявление параметра "n"
{            // вводит область видимости параметра функции
    /* ... */
}            // область видимости параметра функции заканчивается здесь

Область видимости лямбда-выражения

Каждое лямбда-выражение вводит область видимости лямбда-выражения , которая начинается сразу после [ захватов  ] и продолжается до конца { тела } .

Захваты с инициализаторами лямбда-выражения E находятся в области видимости лямбда-выражения, введённой E .

auto lambda = [x = 1, y]() // это лямбда-выражение вводит область видимости лямбда-выражения,
{                          // которая является целевой областью видимости для захвата “x”
    /* ... */
};                         // область видимости лямбда-выражения заканчивается перед точкой с запятой
(начиная с C++14)

Область видимости пространства имен

Каждое определение пространства имён для пространства имён N вводит область видимости пространства имён S , которая включает объявления из каждого определения пространства имён для N .

Для каждой неподружественной передекларации или специализации, целевой областью видимости которой является S или которая содержится в S , следующие части также включаются в область видимости S :

  • Для класса (шаблона) повторного объявления или специализации шаблона класса - часть после class-head-name .
  • Для повторного объявления перечисления - часть после enum-head-name .
  • Для любого другого повторного объявления или специализации - часть после unqualified-id или qualified-id в деклараторе .

Глобальная область видимости - это область видимости пространства имен глобального пространства имен .

namespace V   // определение пространства имён "V"
{             // вводит область видимости пространства имён "S"
    // первая часть области "S" начинается здесь
    void f();
    // первая часть области "S" заканчивается здесь
}
void V::f()   // часть после "f" также является частью области "S"
{
    void h(); // объявляет V::h
}             // вторая часть области "S" заканчивается здесь

Область видимости класса

Каждое объявление класса или шаблона класса C вводит область видимости класса S , которая включает спецификацию-членов из определения класса для C .

Для каждой неподружественной передекларации или специализации, целевой областью видимости которой является S или которая содержится в S , следующие части также включаются в область видимости S :

  • Для класса (шаблона) повторного объявления или специализации шаблона класса - часть после class-head-name .
  • Для повторного объявления перечисления - часть после enum-head-name .
  • Для любого другого повторного объявления или специализации - часть после unqualified-id или qualified-id в деклараторе .
class C       // определение класса "C"
{             // вводит область видимости класса "S"
    // первая часть области видимости "S" начинается здесь
    void f();
    // первая часть области видимости "S" заканчивается здесь
}
void C::f()   // часть после "f" также является частью области видимости "S"
{
    /* ... */
}             // вторая часть области видимости "S" заканчивается здесь

Область видимости перечисления

Каждое объявление перечисления E вводит область перечисления , которая включает список перечислителей из неопакованного (начиная с C++11) объявления перечисления для E (если присутствует).

enum class E // объявление перечисления “E”
{            // вводит область перечисления “S”
    // область “S” начинается здесь
    e1, e2, e3
    // область “S” заканчивается здесь
}

Область видимости параметров шаблона

Каждый template template parameter вводит область видимости параметра шаблона , которая включает весь список параметров шаблона и require clauses (начиная с C++20) этого параметра шаблона шаблона.

Каждое объявление шаблона D вводит область параметров шаблона S , которая простирается от начала списка параметров шаблона D до конца D . Любое объявление вне списка параметров шаблона, которое могло бы находиться в S , вместо этого находится в той же области видимости, что и D .

Только параметры шаблона принадлежат области параметров шаблона, и только области параметров шаблона имеют область параметров шаблона в качестве родительской области.

// объявление шаблона класса "X"
// вводит область параметров шаблона "S1"
template
<
    // область "S1" начинается здесь
    template // шаблонный параметр шаблона "T"
             // вводит другую область параметров шаблона "S2"
    <
        typename T1
        typename T2
    > requires std::convertible_from<T1, T2> // область "S2" заканчивается здесь
    class T,
    typename U
>
class X; // область "S1" заканчивается перед точкой с запятой
namespace N
{
    template <typename T>
    using A = struct X; // "X" находится в той же области, что и объявление
                        // шаблона, а именно в области "N"
}

Область контрактного утверждения

Каждое контрактное утверждение C вводит область контрактного утверждения , которая включает C .

Если постусловие имеет идентификатор , который не является независимым по имени , и постусловие ассоциировано с функцией func потенциально конфликтует с объявлением D , целевая область которого является одной из следующих областей, программа некорректна:

  • Область параметров функции func .
  • Если D ассоциировано с лямбда-выражением , ближайшая охватывающая лямбда-область предусловия.
(since C++26)

Точка объявления

В общем случае, имя становится видимым после локуса его первого объявления, который определяется следующим образом.

Область видимости имени, объявленного в простом объявлении, начинается сразу после декларатора этого имени и до его инициализатора, если таковой имеется.

int x = 32; // внешняя x находится в области видимости
{
    int x = x; // внутренняя x находится в области видимости перед инициализатором (= x)
               // это не инициализирует внутреннюю x значением внешней x (32),
               // это инициализирует внутреннюю x её собственным (неопределённым) значением
}
std::function<int(int)> f = [&](int n){ return n > 1 ? n * f(n - 1) : n; };
// имя функции f находится в области видимости в лямбда-выражении и может
// быть корректно захвачено по ссылке, создавая рекурсивную функцию
const int x = 2; // внешняя x находится в области видимости
{
    int x[x] = {}; // внутренняя x находится в области видимости перед инициализатором (= {}),
                   // но после декларатора (x[x])
                   // в деклараторе внешняя x всё ещё находится в области видимости
                   // это объявляет массив из 2 int
}

Локус объявления класса или шаблона класса находится непосредственно после идентификатора, который именует класс (или template-id , который именует специализацию шаблона) в его class-head . Имя класса или шаблона класса уже находится в области видимости в списке базовых классов.

struct S: std::enable_shared_from_this<S> {}; // S находится в области видимости начиная с двоеточия

Место расположения спецификатора enum или объявления непрозрачного enum (начиная с C++11) находится непосредственно после идентификатора, который именует перечисление.

enum E : int // E находится в области видимости на момент двоеточия
{
    A = sizeof(E)
};

Локус объявления type alias или alias template находится непосредственно после type-id, на который ссылается псевдоним.

using T = int; // внешний T находится в области видимости на точке с запятой
{
    using T = T*; // внутренний T находится в области видимости на точке с запятой,
                  // внешний T всё ещё в области видимости до точки с запятой
                  // эквивалентно T = int*
}

Область видимости для декларатора в using declaration , который не называет конструктор, находится непосредственно после декларатора.

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 находится в области видимости на месте запятой
          Base<next>::value; // Derived::value равно 1
};

Локус перечислителя находится непосредственно после его определения (а не перед инициализатором, как у переменных).

const int x = 12;
{
    enum
    {
        x = x + 1, // перечислитель x находится в области видимости на месте запятой,
                   // внешний x находится в области видимости до запятой,
                   // перечислитель x инициализируется значением 13
        y = x + 1  // y инициализируется значением 14
    };
}

Область видимости для injected-class-name начинается непосредственно после открывающей фигурной скобки определения его класса (или шаблона класса).

template<typename T>
struct Array
//  : std::enable_shared_from_this<Array> // ошибка: внедренное имя класса не в области видимости
    : std::enable_shared_from_this< Array<T> > // OK: имя шаблона Array находится в области видимости
{ // внедренное имя класса Array теперь в области видимости как публичное имя члена
    Array* p; // указатель на Array<T>
};

Область неявного объявления для предопределенной переменной внутри функции __func__ находится непосредственно перед телом функции в определении функции.

(since C++11)


Область видимости декларации структурированной привязки начинается непосредственно после identifier-list , но инициализаторам структурированной привязки запрещено ссылаться на любые из объявляемых имен.

(since C++17)


Область видимости переменной или структурных привязок (since C++17) объявленных в range-declaration цикла range- for loop начинается сразу после range-expression .

std::vector<int> x;
for (auto x : x) // vector x находится в области видимости до закрывающей скобки,
                 // auto x находится в области видимости начиная с закрывающей скобки
{
    // auto x находится в области видимости
}
(since C++11)

Локус параметра шаблона находится непосредственно после его полного параметра шаблона (включая необязательный аргумент по умолчанию).

typedef unsigned char T;
template<
    class T = T, // параметр шаблона T находится в области видимости на месте запятой,
                 // имя typedef для unsigned char находится в области видимости до запятой
    T // параметр шаблона T находится в области видимости
    N = 0
>
struct A
{
};

Локализация постусловия утверждения с идентификатором находится непосредственно после его : .

(since C++26)


Область определения concept начинается сразу после имени концепта, однако определения концептов запрещено ссылаться на объявляемое имя концепта.

(since C++20)

Область определения именованного пространства имён начинается сразу после имени пространства имён.

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
CWG 2793 C++98 объявление extern в блочной области видимости могло
конфликтовать с другим объявлением в родительской области видимости
запрещено

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 6.4 Область видимости [basic.scope]
  • Стандарт C++20 (ISO/IEC 14882:2020):
  • 6.4 Область видимости [basic.scope]
  • Стандарт C++17 (ISO/IEC 14882:2017):
  • 6.3 Область видимости [basic.scope]
  • Стандарт C++14 (ISO/IEC 14882:2014):
  • 3.3 Область видимости [basic.scope]
  • Стандарт C++11 (ISO/IEC 14882:2011):
  • 3.3 Область видимости [basic.scope]
  • Стандарт C++98 (ISO/IEC 14882:1998):
  • 3.3 Декларативные области и области видимости [basic.scope]

Смотрите также

Документация по C для Область видимости