Область видимости
Каждое объявление, которое появляется в программе на C++, видимо только в некоторых, возможно, несмежных областях видимости.
В пределах области видимости можно использовать поиск имён без квалификаторов для сопоставления имени с его объявлением.
Общие
Каждая программа имеет глобальную область видимости, которая содержит всю программу.
Все остальные области видимости S вводятся
- объявлением объявления,
- параметром в списке параметров,
- оператором оператора или
- обработчиком исключений .
S всегда появляются в другой области видимости, которая таким образом содержит S.
Охватывающая область видимости в точке программы — это любая область видимости, которая её содержит; самая маленькая такая область видимости называется непосредственной областью видимости в этой точке.
Область видимости вмешивается между точкой программы P и областью видимости S (которая не содержит P), если она является или содержит S но не содержит P.
Родительская область видимости любой области видимости S , которая не является областью видимости параметра шаблона — это самая маленькая область видимости, которая содержит S и не является областью видимости параметра шаблона.
Если не указано иное:
- Объявление располагается в непосредственной области видимости в его месте объявления.
- Целевая область видимости объявления — это область видимости, в которой оно располагается.
- Любые имена (повторно) введённые объявлением связаны с ним в его целевой области видимости.
Сущность принадлежит области видимости S , если S является целевой областью видимости объявления сущности.
// global scope scope
// scope S T
int x; // ─┐ // program point X
// │
{ // │ ─┐
{ // │ │ ─┐
int y; // │ │ │ // program point 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, диапазон-for(с C++11), while, do-while),
- обработчик исключений или
- составной оператор, который не является составным оператором обработчика исключений
вводит область видимости блока, которая включает оператор или обработчик.
Переменная, принадлежащая области видимости блока, является переменной блока.
int i = 42;
int a[10];
for (int i = 0; i < 10; i++) // inner “i” inhabits the block scope
a[i] = i; // introduced by the for-statement
int j = i; // j = 42Если объявление которое не является независимым от имени объявлением и(с C++26) чья целевая область видимости — область видимости блока S
- составного -оператора тела функции или блока try функции,
| (с C++11) |
- подвыражения оператора выбора или цикла, которое само по себе не является оператором выбора или цикла, или
- обработчика блока try функции
потенциально конфликтует с объявлением, чья целевая область видимости — родительская область видимости S, программа некорректна.
if (int x = f()) // declares “x”
{ // the if-block is a substatement of the if-statement
int x; // error: redeclaration of “x”
}
else
{ // the else-block is also a substatement of the if-statement
int x; // error: redeclaration of “x”
}Область видимости параметра функции
Каждое объявление параметра P вводит область видимости параметра функции, которая включает P.
- Если объявленный параметр является частью списка параметров объявления функции:
- Если объявление функции является определением функции, введённая область видимости расширяется до конца определения функции.
- В противном случае (объявление функции является прототипом функции), введённая область видимости расширяется до конца декларатора функции.
- В обоих случаях область видимости не включает место объявления функции.
| (с C++11) |
| (с C++17) |
| (с C++20) |
int f(int n) // the declaration of the parameter “n”
{ // introduces a function parameter scope
/* ... */
} // the function parameter scope ends here Область видимости лямбда-выраженияКаждое выражение лямбда вводит область видимости лямбда-выражения, которая начинается сразу после Захваты с инициализаторами выражения лямбда auto lambda = [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 | (с C++14) |
Область видимости пространства имён
Каждое определение пространства имён для пространства имён N вводит область видимости пространства имён S , которая включает объявления для каждого определения пространства имён для N.
Для каждого переобъявления или специализации, не являющегося другом, чья целевая область видимости — S или содержится в S, следующие части также включены в область видимости S:
- Для переобъявления или специализации класса (шаблона) — часть после имени класса class-head-name.
- Для переобъявления перечисления — часть после имени перечисления enum-head-name.
- Для любого другого переобъявления или специализации — часть после unqualified-id или qualified-id декларатора.
Глобальная область видимости — область видимости глобального пространства имён.
namespace V // the namespace definition of “V”
{ // introduces a namespace scope “S”
// the first part of scope “S” begins here
void f();
// the first part of scope “S” ends here
}
void V::f() // the portion after “f” is also a part of scope “S”
{
void h(); // declares V::h
} // the second part of scope “S” ends hereОбласть видимости класса
Каждое объявление класса или шаблона класса C вводит область видимости класса S , которая включает спецификацию члена определения класса C.
Для каждого переобъявления или специализации, не являющегося другом, чья целевая область видимости — S или содержится в S, следующие части также включены в область видимости S:
- Для переопределения класса (шаблона) или специализации шаблона класса, часть после его имени-заголовка-класса.
- Для переопределения перечисления, часть после его имени-заголовка-перечисления.
- Для любого другого переопределения или специализации, часть после неквалифицированного-идентификатора или квалифицированного-идентификатора декларатора.
class C // the class definition of “C”
{ // introduces a class scope “S”
// the first part of scope “S” begins here
void f();
// the first part of scope “S” ends here
}
void C::f() // the portion after “f” is also a part of scope “S”
{
/* ... */
} // the second part of scope “S” ends hereОбласть перечисления
Каждая декларация перечисления E вводит область перечисления, которая включает список-перечислителей не-непрозрачного(с C++11) объявления перечисления E (если оно присутствует).
enum class E // the enumeration declaration of “E”
{ // introduces an enumeration scope “S”
// scope “S” begins here
e1, e2, e3
// scope “S” ends here
}Область параметра шаблона
Каждый параметр шаблона шаблона вводит область параметра шаблона, которая включает весь список параметров шаблона и условия-требований(с C++20) этого параметра шаблона шаблона.
Каждое объявление шаблона D вводит область параметра шаблона S, которая простирается от начала списка параметров шаблона D до конца D. Любое объявление вне списка параметров шаблона, которое должно находиться в S вместо этого, находится в той же области, что и D.
// the class template declaration of “X”
// introduces a template parameter scope “S1”
template
<
// scope “S1” begins here
template // the template template parameter “T”
// introduces another template parameter scope “S2”
<
typename T1
typename T2
> requires std::convertible_from<T1, T2> // scope “S2” ends here
class T,
typename U
>
class X; // scope “S1” ends before the semicolonТочка объявления
В общем случае имя становится видимым после локуса его первого объявления, которое расположено следующим образом.
Локус имени, объявленного в простом объявлении, находится сразу после декларатора этого имени и перед его инициализатором, если таковой имеется.
int x = 32; // outer x is in scope
{
int x = 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 = [&](int n){ return n > 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 functionconst int x = 2; // outer x is in scope
{
int x[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
}Локус объявления класса или шаблона класса находится сразу после идентификатора, который называет класс (или идентификатор-шаблона, который называет специализацию шаблона) в его заголовке-класса. Имя класса или шаблона класса уже находится в области видимости в списке базовых классов.
struct S: std::enable_shared_from_this<S> {}; // S is in scope at the colonЛокус спецификатора перечисления или объявления непрозрачного перечисления(с C++11) находится сразу после идентификатора, который называет перечисление.
enum E : int // E is in scope at the colon
{
A = sizeof(E)
};Локус объявления псевдонима типа или шаблона псевдонима находится сразу после идентификатора типа, к которому относится псевдоним.
using T = int; // outer T is in scope at the semicolon
{
using T = T*; // inner T is in scope at the semicolon,
// outer T is still in scope before the semicolon
// same as T = int*
}Локус декларатора в объявлении using, которое не называет конструктор, находится сразу после декларатора.
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 in scope at the comma
Base<next>::value; // Derived::value is 1
};Локус перечислителя находится сразу после его определения (а не перед инициализатором, как это происходит для переменных).
const int x = 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 13
y = x + 1 // y is initialized to 14
};
}Локус встроенного имени класса находится сразу после открывающей фигурной скобки его определения класса (или шаблона класса).
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>
};| Локус неявного объявления для предопределенной переменной в локальной функции | (с C++11) |
| Локус объявления связанных структур находится сразу после списка-идентификаторов, но инициализаторы связанных структур запрещено ссылаться на любые из объявляемых имён. | (с C++17) |
| Локус переменной или связанных структур(с C++17) объявленных в объявлении-диапазона цикла range-for находится сразу после выражения-диапазона. std::vector<int> x;
for (auto x : 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
} | (с C++11) |
Локус параметра шаблона находится сразу после его полного параметра шаблона (включая необязательное аргумент по умолчанию).
typedef unsigned char T;
template<
class T = T, // template parameter T is in scope at the comma,
// typedef name of unsigned char is in scope before the comma
T // template parameter T is in scope
N = 0
>
struct A
{
};| Локус определения концепции находится сразу после имени концепции, но определения концепции запрещено ссылаться на имя объявляемой концепции. | (с C++20) |
Локус именованного определения пространства имён находится сразу после имени пространства имён.
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2023):
- 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 документация по Области видимости |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/scope