Scope
Каждая декларация , появляющаяся в программе на C++, видима только в некоторых возможно несмежных областях видимости .
В пределах области видимости, поиск неквалифицированного имени может использоваться для связывания имени с его объявлением.
Общее
Каждая программа имеет глобальную область видимости , которая содержит всю программу.
Каждая другая область видимости
S
вводится одним из следующих способов:
- объявление declaration
- параметр в parameter list
- оператор statement
- обработчик handler
| (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.
Область видимости блока
Каждый
- оператор выбора ( if , switch ),
- оператор цикла ( for , range- for (начиная с C++11) , while , do - while ),
- обработчик , или
- составной оператор , который не является составным-оператором обработчика
вводит область видимости блока , которая включает оператор или обработчик.
Переменная, принадлежащая области видимости блока, называется блочной переменной (также известной как локальная переменная).
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
- составная-инструкция compound-statement тела функции или функционального try блока ,
|
(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
.
- Если объявленный параметр находится в списке параметров объявления функции :
-
- Если объявление функции является определением функции , введенная область видимости распространяется до конца определения функции.
- В противном случае (объявление функции является прототипом функции), введенная область видимости распространяется до конца декларатора функции.
- В обоих случаях область видимости не включает точку объявления функции.
|
(начиная с C++11) |
|
(начиная с C++17) |
|
(начиная с 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" }
Область контрактного утверждения
Каждое
контрактное утверждение
Если
постусловие
имеет
идентификатор
, который не является
независимым по имени
, и постусловие ассоциировано с функцией
func
потенциально конфликтует
с объявлением
|
(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) |
Область определения именованного пространства имён начинается сразу после имени пространства имён.
|
Этот раздел не завершён
Причина: остаток [basic.scope.pdecl] |
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам 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
для
Область видимости
|