Spec-Zone.ru › C++

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

Каждое объявление, которое появляется в программе на 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)
  • Если объявленный параметр является частью списка параметров выражения requires, введённая область видимости расширяется до конца { последовательность требований }.
(с C++20)
int f(int n)  // the declaration of the parameter “n”
{             // introduces a function parameter scope
    /* ... */
}             // the function parameter scope ends here

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

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

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

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 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

Локус спецификатора перечисления или объявления непрозрачного перечисления(с 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>
};

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

(с 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API