Область видимости
Каждое объявление, встречающееся в программе на C++, видно только в некоторых, возможно несвязных, областях видимости .
В пределах области видимости для связывания имени с его объявлением можно использовать поиск неквалифицированного имени.
Общие сведения
У каждой программы есть глобальная область видимости , которая содержит всю программу.
Любая другая область видимости S вводится одним из следующих элементов:
- объявлением
- параметром в списке параметров
- оператором
- обработчиком
| (начиная с C++26) |
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, цикл range-for(начиная с C++11), while, do-while),
| (начиная с C++26) |
- обработчик или
- составной оператор, который не является compound-statement обработчика,
вводит область видимости блока, включающую этот оператор или обработчик.
Переменная, принадлежащая области видимости блока, называется переменной блока .
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
Если объявление принадлежит области видимости блока S и объявляет функцию либо использует спецификатор extern, объявление не должно быть связано с именованным модулем (начиная с C++20), его целевой областью видимости является более внешняя область видимости (самая внутренняя внешняя область видимости пространства имён), но имя связывается с ним в непосредственной области видимости S.
Если объявление, которое не является объявлением с независимым именем и(начиная с C++26), связывающее имя в области видимости блока S, принадлежит
- compound-statement тела функции или блока 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”
}
void g(int i)
{
extern int i; // error: redeclaration of “i”
}
Область видимости параметров функции
Каждое объявление параметра 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, включающую member-specification определения класса C.
Для каждого повторного объявления или специализации, не являющихся дружественными, целевая область видимости которых — S или содержится в S, следующие фрагменты также входят в область видимости S:
- Для повторного объявления класса (шаблона) или специализации шаблона класса — фрагмент после его class-head-name.
- Для повторного объявления перечисления — фрагмент после его enum-head-name.
- Для любого другого повторного объявления или специализации — фрагмент после unqualified-id или qualified-id декларатора.
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 вводит область видимости перечисления, включающую enumerator-list объявления перечисления E (если оно есть) без базового типа(начиная с C++11).
enum class E // the enumeration declaration of “E”
{ // introduces an enumeration scope “S”
// scope “S” begins here
e1, e2, e3
// scope “S” ends here
}
Область видимости параметров шаблона
Каждый параметр-шаблон шаблона вводит область видимости параметров шаблона, включающую весь список параметров шаблона и предложения require(начиная с 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
namespace N
{
template <typename T>
using A = struct X; // “X” inhabits the same scope as template
// declaration, namely the scope of “N”
}
Область видимости утверждения контрактаКаждое утверждение контракта Если утверждение постусловия содержит identifier, не являющийся независимым от имени, и утверждение постусловия связано с функцией
| (начиная с C++26) |
Точка объявления
Как правило, имя становится видимым после точки положения его первого объявления, которая определяется следующим образом.
Точка положения имени, объявленного в простом объявлении, находится сразу после декларатора этого имени и перед его инициализатором, если он есть.
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 function
const 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
Точка положения спецификатора enum или непрозрачного объявления перечисления(начиная с 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) |
| Точка положения объявления структурированной привязки находится сразу после identifier-list, однако инициализаторам структурированной привязки запрещено ссылаться на любое из объявляемых имён. | (начиная с C++17) |
| Точка положения переменной или структурированных привязок(начиная с C++17), объявленных в item-declaration цикла range-for, находится сразу после range-initializer.
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
{
};
| Точка положения утверждения постусловия с identifier находится сразу после его | (начиная с C++26) |
| Точка положения определения концепта находится сразу после имени концепта, однако определениям концептов запрещено ссылаться на объявляемое имя концепта. | (начиная с C++20) |
Точка положения именованного определения пространства имён находится сразу после имени пространства имён.
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были ретроспективно применены к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение согласно опубликованной версии | Корректное поведение |
|---|---|---|---|
| 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 для области видимости |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/scope