6 Basic concepts [basic]

6.3 Scope [basic.scope]

6.3.1 Declarative regions and scopes [basic.scope.declarative]

Каждое имя вводится в некоторой части текста программы, называемой a , которая является самой большой частью программы, в которой это имя , то есть в которой это имя может использоваться как неквалифицированное имя для ссылки на один и тот же объект. В общем, каждое конкретное имя допустимо только в пределах некоторой, возможно, несмежной части текста программы, называемой его . Чтобы определить объем объявления, иногда удобно обратиться к объекту объявления. Область действия объявления такая же, как и ее потенциальная область, если только потенциальная область не содержит другое объявление с тем же именем. В этом случае потенциальная область действия объявления во внутренней (содержащейся) декларативной области исключается из области действия объявления во внешней (содержащей) декларативной области.declarative regionvalidscopepotential scope

[ Example: В

int j = 24;
int main() {
  int i = j, j;
  j = 42;
}

идентификаторj объявляется дважды как имя (и используется дважды). Декларативная область первогоj включает весь пример. Потенциальная область действия первогоj начинается сразу после этогоj и продолжается до конца программы, но ее (фактическая) область действия исключает текст между символами, и }. Декларативная область второго объявления j (j непосредственно перед точкой с запятой) включает весь текст между{ и}, но его потенциальная область исключает объявлениеi. Область действия второго объявленияj совпадает с его потенциальной областью. ]end example

Имена, объявленные объявлением, вводятся в область видимости, в которой происходит объявление, за исключением того, что наличие a friend specifier, некоторые виды использования elaborated-type-specifierи using-directives изменяют это общее поведение.

Учитывая набор объявлений в одной декларативной области, каждое из которых указывает одно и то же неквалифицированное имя,

  • все они должны относиться к одному и тому же объекту или все относиться к функциям и шаблонам функций; или

  • ровно одно объявление должно объявлять имя класса или имя перечисления, которое не является именем typedef, а все другие объявления должны ссылаться на одну и ту же переменную, нестатический член данных или перечислитель, или все они относятся к функциям и шаблонам функций; в этом случае имя класса или имя перечисления hidden. [ Note: Имя пространства имен или имя шаблона класса должно быть уникальным в своей декларативной области ([namespace.alias], пункт[temp]). ] end note

[ Note: Эти ограничения применяются к декларативной области, в которой вводится имя, которая не обязательно совпадает с областью, в которой происходит объявление. В частности, elaborated-type-specifiers и friend declarations может ввести (возможно, невидимое) имя во включающее пространство имен; эти ограничения распространяются на этот регион. Локальные объявления extern ([basic.link]) могут вводить имя в декларативную область, где появляется объявление, а также вводить (возможно, не видимое) имя во включающее пространство имен; эти ограничения распространяются на оба региона. ]end note

[ Note: Правила поиска имени кратко изложены в[basic.lookup]. ]end note

6.3.2 Point of declaration [basic.scope.pdecl]

Дляpoint of declaration имени ставится сразу после его завершенияdeclarator и перед initializer(если есть), за исключением случаев, указанных ниже. [Example:

unsigned char x = 12;
{ unsigned char x = x; }

Здесь второйx инициализируется своим (неопределенным) значением. ]end example

[ Имя из внешней области видимости остается видимым до момента объявления имени, которое его скрывает. [Note: Example:

const int  i = 2;
{ int  i[i]; }

объявляет массив из двух целых чисел в области видимости блока. ] ]end exampleend note

Точка объявления для класса или шаблона класса, сначала объявленного a, class-specifierнаходится сразу после identifierили simple-template-id(если есть) в его class-head. Точка объявления для перечисления находится сразу после identifier(если есть) либо в его, enum-specifierлибо в его первом opaque-enum-declaration, в зависимости от того, что наступит раньше. Точка объявления псевдонима или шаблона псевдонима следует сразу за тем, type-idна который ссылается псевдоним.

Точка объявления using-declarator, которая не называет конструктор, находится сразу после using-declarator.

Точка объявления перечислителя находится сразу после его enumerator-definition. [Example:

const int x = 12;
{ enum { x = x }; }

Здесь перечислительx инициализируется значением константыx, а именно 12. ]end example

После точки объявления члена класса имя члена можно искать в области его класса. [ Это верно, даже если класс является неполным. Например,Note:

struct X {
  enum E { z = 16 };
  int b[X::z];      // OK
};

end note]

Точка объявления класса, впервые объявленного в файле, elaborated-type-specifierвыглядит следующим образом:

Точка объявления для an injected-class-name следует сразу за открывающей скобкой определения класса.

Точка объявления для локальной предопределенной переменной ([dcl.fct.def]) находится непосредственно перед function-bodyопределением функции.

Точка объявления параметра шаблона - сразу после его завершения template-parameter. [Example:

typedef unsigned char T;
template<class T
  = T     // lookup finds the typedef name of unsigned char
  , T     // lookup finds the template parameter
    N = 0> struct A { };

end example]

[ Note: Дружественные объявления относятся к функциям или классам, которые являются членами ближайшего включающего пространства имен, но они не вводят новые имена в это пространство имен ([namespace.memdef]). Объявления функций в области видимости блока и объявления переменных со extern спецификатором в области видимости блока относятся к объявлениям, которые являются членами включающего пространства имен, но они не вводят новые имена в эту область. ]end note

[ Note: Для создания экземпляра шаблона см[temp.point].. ]end note

6.3.3 Block scope [basic.scope.block]

Имя, объявленное в a,block является локальным для этого блока; это есть block scope. Его потенциальная область действия начинается с егоpoint of declaration и заканчивается в конце его блока. Переменная, объявленная в области видимости блока, - этоlocal variable.

Потенциальная область видимости имени параметра функции (включая имя, появляющееся в a lambda-declarator) или предопределенной переменной функции в afunction definition начинается с точки ее объявления. Если функция имеет function-try-blockпотенциальную область видимости параметра или предопределенной переменной, локальной для функции, заканчивается в конце последнего связанного обработчика, в противном случае она заканчивается в конце самого внешнего блока определения функции. Имя параметра не должно повторно объявляться ни во внешнем блоке определения функции, ни во внешнем блоке любого обработчика, связанного с a function-try-block.

Имя, объявленное в объекте, exception-declaration является локальным по отношению к handlerобъекту, и его нельзя повторно объявлять во внешнем блоке handler.

Имена объявлены в init-statement, то for-range-declarationи в conditionизif,while,for, и switch заявления являются локальными кif,while, forилиswitch заявление ( в том числе и контролируемое заявление), и не может быть повторно объявлен в последующем состоянии этого заявления , ни в наружном блоке ( или, дляif оператора, любой из самых внешних блоков) контролируемого оператора; см[stmt.select].

6.3.4 Function prototype scope [basic.scope.proto]

В объявлении функции или в любом деклараторе функции, кроме декларатора afunction definition, имена параметров (если предоставлены) имеют область прототипа функции, которая заканчивается в конце ближайшего включающего декларатора функции.

6.3.5 Function scope [basic.funscope]

Labels имеютfunction scope и могут использоваться в любом месте функции, в которой они объявлены. Только ярлыки имеют область действия.

6.3.6 Namespace scope [basic.scope.namespace]

Декларативная область - namespace-definitionэто его namespace-body. Объекты, объявленные в a, namespace-bodyназываютсяmembers принадлежащими пространству имен, а имена, введенные этими объявлениями в декларативную область пространства имен, называютсяmember names принадлежащими пространству имен. Имя члена пространства имен имеет область пространства имен. Его потенциальная область действия включает пространство имен, начиная с имениpoint of declaration ; и для каждого, using-directiveкоторый назначает пространство имен члена, потенциальная область действия члена включает ту часть потенциальной области видимости, using-directiveкоторая следует за точкой объявления члена. [Example:

namespace N {
  int i;
  int g(int a) { return a; }
  int j();
  void q();
}
namespace { int l=1; }
// the potential scope of l is from its point of declaration to the end of the translation unit

namespace N {
  int g(char a) {   // overloads N​::​g(int)
    return l+a;     // l is from unnamed namespace
  }

  int i;            // error: duplicate definition
  int j();          // OK: duplicate function declaration

  int j() {         // OK: definition of N​::​j()
    return g(i);    // calls N​::​g(int)
  }
  int q();          // error: different return type
}

end example]

На член пространства имен также можно ссылаться после того, как​::​ оператор разрешения области видимости ([expr.prim]) применен к имени его пространства имен или имени пространства имен, которое назначает пространство имен члена в using-directive; см[namespace.qual].

Самая внешняя декларативная область единицы перевода - это также пространство имен, называемоеglobal namespace. Имя, объявленное в глобальном пространстве имен, имеетglobal namespace scope (также называется global scope). Потенциальная область видимости такого имени начинаетсяpoint of declaration и заканчивается в конце единицы трансляции, которая является ее декларативной областью. Имя с глобальной областью пространства имен называется global name.

6.3.7 Class scope [basic.scope.class]

Потенциальная область видимости имени, объявленного в классе, состоит не только из декларативной области, следующей за точкой объявления имени, но также из всех тел функций, аргументов по умолчанию noexcept-specifiersи brace-or-equal-initializers нестатических элементов данных в этом классе (включая такие вещи в вложенные классы).

Имя,N используемое в классе,S должно ссылаться на одно и то же объявление в его контексте и при повторной оценке в завершенной областиS. Нарушение этого правила не требует диагностики.

Имя, объявленное в функции-члене, скрывает объявление с тем же именем, область действия которого простирается до конца класса функции-члена или за его пределами.

Потенциальная область действия объявления, которая простирается до конца определения класса или за его пределами, также распространяется на области, определенные определениями его членов, даже если члены определены лексически вне класса (это включает определения статических элементов данных, определения вложенных классов, и определения функций-членов, включая тело функции-члена и любую часть декларативной части таких определений, которая следует за declarator-id, включая a parameter-declaration-clauseи anydefault arguments).

[Example:

typedef int  c;
enum { i = 1 };

class X {
  char  v[i];                       // error: i refers to ​::​i but when reevaluated is X​::​i
  int  f() { return sizeof(c); }    // OK: X​::​c
  char  c;
  enum { i = 2 };
};

typedef char*  T;
struct Y {
  T  a;                             // error: T refers to ​::​T but when reevaluated is Y​::​T
  typedef long  T;
  T  b;
};

typedef int I;
class D {
  typedef I I;                      // error, even though no reordering involved
};

end example]

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

  • в рамках своего класса (как описано выше) или класса derived из своего класса,

  • после. применения оператора к выражению типа его класса ([expr.ref]) или класса, производного от его класса,

  • после-> применения оператора к указателю на объект его класса ([expr.ref]) или класса, производного от его класса,

  • после того, как​::​ оператор разрешения области видимости ([expr.prim]) применен к имени его класса или класса, производного от его класса.

6.3.8 Enumeration scope [basic.scope.enum]

Имяscoped enumerator имеет enumeration scope. Его потенциальная область действия начинается в точке объявления и заканчивается в конце enum-specifier.

6.3.9 Template parameter scope [basic.scope.temp]

Декларативная область имени параметра шаблона шаблона template-parameter- наименьшая, template-parameter-list в которой имя было введено.

Декларативная область имени параметра шаблона шаблона - наименьшая, template-declarationв которой имя было введено. К этой декларативной области принадлежат только имена параметров шаблона; любой другой вид имени, введенный с помощью declarationa template-declaration, вместо этого вводится в ту же декларативную область, где он был бы введен в результате нешаблонного объявления с тем же именем. [Example:

namespace N {
  template<class T> struct A { };               // #1
  template<class U> void f(U) { }               // #2
  struct B {
    template<class V> friend int g(struct C*);  // #3
  };
}

Декларативная областьT,U иV являются template-declarations по линиям # 1, # 2 и # 3, соответственно. Но именаA,f,g иC все они принадлежат к одной и той же декларативной области , а именно - namespace-bodyизN. (g по-прежнему считается принадлежащей этой декларативной области, несмотря на то, что она была скрыта во время поиска квалифицированного и неквалифицированного имени.) ]end example

Потенциальная область действия имени параметра шаблона начинается с егоpoint of declaration и заканчивается в конце его декларативной области. [ Note: Это означает, что a template-parameterможет использоваться в объявлении последующих template-parameters аргументов и их аргументов по умолчанию, но не может использоваться в предшествующих template-parameters аргументах или их аргументах по умолчанию. Например,

template<class T, T* p, class U = T> class X { /* ... */ };
template<class T> void f(T* p = new T);

Это также означает, что a template-parameterможет использоваться в спецификации базовых классов. Например,

template<class T> class X : public Array<T> { /* ... */ };
template<class T> class Y : public T { /* ... */ };

Использование параметра шаблона в качестве базового класса подразумевает, что класс, используемый в качестве аргумента шаблона, должен быть определен, а не просто объявлен при создании экземпляра шаблона класса. ]end note

Декларативная область имени параметра шаблона вложена в непосредственно включающую декларативную область. [ Note: В результате template-parameterhides любой объект с тем же именем во включающей области. [Example:

typedef int N;
template<N X, typename N, template<N Y> class T> struct A;

Здесь,X является параметром шаблона не-типа типаint иY является параметром шаблона не-типа того же типа в качестве второго параметра шаблона из A. ] ]end exampleend note

[ Note: Поскольку имя параметра шаблона не может быть повторно объявлено в пределах его потенциальной области ([temp.local]), область действия параметра шаблона часто является его потенциальной областью. Однако имя параметра шаблона все еще можно скрыть; см[temp.local]. ]end note

6.3.10 Name hiding [basic.scope.hiding]

Имя может быть скрыто явным объявлением того же имени во вложенной декларативной области или производном классе ([class.member.lookup]).

class name Илиenumeration name могут быть скрыты по имени переменной, члена данных, функции или счетчику , объявленного в том же объеме. Если имя класса или перечисления и переменная, член данных, функция или перечислитель объявлены в одной и той же области (в любом порядке) с одним и тем же именем, имя класса или перечисления скрыто везде, где переменная, член данных, функция или имя перечислителя видно.

В определении функции-члена объявление имени в области видимости блока скрывает объявление члена класса с тем же именем; см[basic.scope.class]. Объявление члена в aderived class скрывает объявление члена одноименного базового класса; см[class.member.lookup].

Во время поиска имени, уточненного именем пространства имен, объявления, которые в противном случае стали бы видимыми с помощью a, using-directiveмогут быть скрыты объявлениями с тем же именем в пространстве имен, содержащем using-directive; см[namespace.qual].

Если имя находится в области видимости и не скрыто, оно считается скрытымvisible.