6 Basic concepts [basic]

6.4 Name lookup [basic.lookup]

Правила поиска имен применяются единообразно ко всем именам (включая typedef-names, namespace-names ([basic.namespace]) и class-names ([class.name])) везде, где грамматика допускает такие имена в контексте, обсуждаемом определенным правилом. Поиск имени связывает использование имени с набором объявлений ([basic.def]) этого имени. Объявления, найденные с помощью поиска по имени, должны либо все объявлять один и тот же объект, либо все должны объявлять функции; в последнем случае говорят, что объявления образуют набор перегруженных функций ([over.load]). Overload resolution происходит после успешного поиска имени. access rules Считаются только один раз имя поиска и разрешения перегрузки функции (если применимо) удалось. Только после поиска имени, разрешения перегрузки функции (если применимо) и проверки доступа атрибуты, введенные объявлением имени, используются далее при обработке выражения (пункт [expr]).

Имя, «найденное в контексте выражения», ищется как неквалифицированное имя в области, в которой найдено выражение.

injected-class-name Класса также считается членом этого класса в целях сокрытия имен и поиска.

[ Note: [basic.link] обсуждает вопросы связи. Понятия области видимости, точки объявления и сокрытия имени обсуждаются в [basic.scope]. ] end note

6.4.1 Unqualified name lookup [basic.lookup.unqual]

Во всех случаях, перечисленных в [basic.lookup.unqual], области действия ищутся для объявления в порядке, указанном в каждой из соответствующих категорий; Поиск имени заканчивается, как только для имени найдено объявление. Если объявление не найдено, программа имеет неправильный формат.

Объявления из пространства имен, обозначенного символом a, using-directiveстановятся видимыми в пространстве имен, содержащем using-directive; см [namespace.udir]. Для целей правил поиска неквалифицированных имен, описанных в [basic.lookup.unqual], объявления из пространства имен, назначенного using-directiveэлементом, считаются членами этого включающего пространства имен.

Поиск неполного имени, используемого в postfix-expressionкачестве вызова функции, описан в [basic.lookup.argdep]. [ Note: Для определения (во время синтаксического анализа), является ли выражение postfix-expressionдля вызова функции, применяются обычные правила поиска имени. Правила [basic.lookup.argdep] не влияют на синтаксическую интерпретацию выражения. Например,

typedef int f;
namespace N {
  struct A {
    friend void f(A &);
    operator int();
    void g(A a) {
      int i = f(a);  // f is the typedef, not the friend function: equivalent to int(a)
    }
  };
}

Поскольку выражение не является вызовом функции, argument-dependent name lookup не применяется и функция друга f не найдена. ] end note

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

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

В определении функции, которая является членом пространства имен N, имя, используемое после функции, declarator-id29 должно быть объявлено до его использования в блоке, в котором оно используется, или в одном из его включающих блоков ([stmt.block]), или должно быть объявлено перед его использованием в пространство имен N или, если N это вложенное пространство имен, должно быть объявлено перед его использованием в одном из Nвключающих пространств имен. [Example:

namespace A {
  namespace N {
    void f();
  }
}
void A::N::f() {
  i = 5;
  // The following scopes are searched for a declaration of i:
  // 1) outermost block scope of A​::​N​::​f, before the use of i
  // 2) scope of namespace N
  // 3) scope of namespace A
  // 4) global scope, before the definition of A​::​N​::​f
}

end example]

Имя , используемое в определении класса X внешней функции члена тела, аргумент по умолчанию, noexcept-specifier, brace-or-equal-initializerиз нестатического элемента данных или определения вложенного класса ,30 должны быть объявлен в одном из следующих способов:

  • перед его использованием в классе X или быть членом базового класса X ([class.member.lookup]), или

  • if X является a nested class of class Y, до определения X in Y, или должен быть членом базового класса Y (этот поиск применяется, в свою очередь, к Yохватывающим классам, начиная с самого внутреннего включающего класса),31 или

  • если X является local class или является вложенным классом локального класса, перед определением класса X в блоке, включающем определение класса X, или

  • if X является членом пространства имен N, или является вложенным классом класса, который является членом N, или является локальным классом, или вложенным классом в локальном классе функции, которая является членом N, до определения класса X в пространстве имен N или в одном из Nзакрывающих пространств имен.

[Example:

namespace M {
  class B { };
}
namespace N {
  class Y : public M::B {
    class X {
      int a[i];
    };
  };
}

// The following scopes are searched for a declaration of i:
// 1) scope of class N​::​Y​::​X, before the use of i
// 2) scope of class N​::​Y, before the definition of N​::​Y​::​X
// 3) scope of N​::​Y's base class M​::​B
// 4) scope of namespace N, before the definition of N​::​Y
// 5) global scope, before the definition of N

end example] [ Note: При поиске предыдущего объявления класса или функции, введенного friend объявлением, области за пределами самой внутренней области охватывающего пространства имен не рассматриваются; см [namespace.memdef]. ] [ далее описывает ограничения на использование имен в определении класса. далее описывает ограничения на использование имен в определениях вложенных классов. далее описывает ограничения на использование имен в определениях локальных классов. ] end noteNote: [basic.scope.class] [class.nest] [class.local] end note

Для членов класса должно быть объявлено Xимя, используемое в теле функции-члена, в аргументе по умолчанию, в a noexcept-specifier, в brace-or-equal-initializera non-static data memberили в определении члена класса вне определения X, следующее за членом. declarator-id32одним из следующих способов:

  • перед его использованием в блоке, в котором он используется, или во включающем блоке ([stmt.block]), или

  • должен быть членом класса X или быть членом базового класса X ([class.member.lookup]), или

  • if X является nested class классом Y, должен быть членом Yили должен быть членом базового класса Y (этот поиск применяется, в свою очередь, к Yвключающим классам, начиная с самого внутреннего включающего класса),33 или

  • если X является local class или является вложенным классом локального класса, перед определением класса X в блоке, включающем определение класса X, или

  • if X является членом пространства имен Nили является вложенным классом класса, который является членом N, или является локальным классом или вложенным классом в локальном классе функции, которая является членом N, до использования имени, в пространстве имен N или в одном из Nвключающих пространств имен.

[Example:

class B { };
namespace M {
  namespace N {
    class X : public B {
      void f();
    };
  }
}
void M::N::X::f() {
  i = 16;
}

// The following scopes are searched for a declaration of i:
// 1) outermost block scope of M​::​N​::​X​::​f, before the use of i
// 2) scope of class M​::​N​::​X
// 3) scope of M​::​N​::​X's base class B
// 4) scope of namespace M​::​N
// 5) scope of namespace M
// 6) global scope, before the definition of M​::​N​::​X​::​f

end example] [ Note: [class.mfct] и [class.static] далее опишите ограничения на использование имен в определениях функций-членов. [class.nest] далее описывает ограничения на использование имен в рамках вложенных классов. [class.local] далее описывает ограничения на использование имен в определениях локальных классов. ] end note

Поиск имени для имени, используемого в определении friend function определенного встроенного в классе, предоставляющем дружбу, должен выполняться, как описано для поиска в определениях функций-членов. Если friend функция не определена в классе, предоставляющем дружбу, поиск имени в friend определении функции должен выполняться, как описано для поиска в определениях функций-членов пространства имен.

В friend объявлении, называющем функцию-член, имя, используемое в деклараторе функции, а не часть a template-argument в, declarator-idсначала ищется в области действия class ([class.member.lookup]) функции-члена . Если он не найден или если имя является частью a template-argumentв declarator-id, поиск выполняется так, как описано для неквалифицированных имен в определении класса, предоставляющего дружбу. [Example:

struct A {
  typedef int AT;
  void f1(AT);
  void f2(float);
  template <class T> void f3();
};
struct B {
  typedef char AT;
  typedef float BT;
  friend void A::f1(AT);      // parameter type is A​::​AT
  friend void A::f2(BT);      // parameter type is B​::​BT
  friend void A::f3<AT>();    // template argument is B​::​AT
};

end example]

Во время поиска имени, используемого в качестве default argument в функции parameter-declaration-clauseили используемого в expressionэлементе mem-initializerдля конструктора ([class.base.init]), имена параметров функции видны и скрывают имена сущностей, объявленных в областях блока, класса или пространства имен, содержащих объявление функции. [ Note: [dcl.fct.default] далее описывает ограничения на использование имен в аргументах по умолчанию. [class.base.init] далее описывает ограничения на использование имен в ctor-initializer. ]end note

Во время поиска имени, используемого в constant-expressionобъекте enumerator-definition, ранее объявленные enumerators в перечислении становятся видимыми и скрывают имена сущностей, объявленных в областях блока, класса или пространства имен, содержащих enum-specifier.

Имя, используемое в определении static data member класса X (после qualified-id статического члена) ищется, как если бы имя использовалось в функции-члене класса X. [ Note: [class.static.data] далее описывает ограничения на использование имен в определении элемента static данных. ] end note

Если переменный член пространства имен определен вне области его пространства имен, то любое имя, которое появляется в определении члена (после declarator-id), ищется так, как если бы определение члена произошло в его пространстве имен. [Example:

namespace N {
  int i = 4;
  extern int j;
}

int i = 2;

int N::j = i;       // N​::​j == 4

end example]

Имя, используемое в обработчике для a function-try-block, ищется так, как если бы имя использовалось во внешнем блоке определения функции. В частности, имена параметров функции не должны повторно объявляться exception-declarationни в самом внешнем блоке обработчика, ни в самом внешнем блоке обработчика function-try-block. Имена, объявленные во внешнем блоке определения функции, не обнаруживаются при поиске в области обработчика для function-try-block. [ Note: Но имена параметров функции найдены. ] end note

[ Note: Правила поиска имени в определениях шаблонов описаны в [temp.res]. ] end note

Это относится к неквалифицированным именам, которые встречаются, например, в типе или аргументе по умолчанию в parameter-declaration-clauseили используются в теле функции.

Это относится к неквалифицированным именам, следующим за именем класса; такое имя может использоваться в base-clauseили может использоваться в определении класса.

Этот поиск применяется независимо от того, вложено ли определение X в Yопределение или Xпоявляется ли определение в области пространства имен, включающей Yопределение ([class.nest]).

То есть неквалифицированное имя, которое встречается, например, в типе в parameter-declaration-clauseили в noexcept-specifier.

Этот поиск применяется независимо от того, определена X ли функция-член в определении класса или функция-член определена в области пространства имен, содержащей Xопределение.

6.4.2 Argument-dependent name lookup [basic.lookup.argdep]

Когда postfix-expressionin a function call является an unqualified-id, unqualified lookup могут быть найдены другие пространства имен, не рассматриваемые в обычном режиме , и в этих пространствах имен могут быть найдены дружественные функции области пространства имен или объявления шаблонов функций ([class.friend]), которые иным образом не видны. Эти изменения в поиске зависят от типов аргументов (а для аргументов шаблона шаблона - пространства имен аргумента шаблона). [Example:

namespace N {
  struct S { };
  void f(S);
}

void g() {
  N::S s;
  f(s);     // OK: calls N​::​f
  (f)(s);   // error: N​::​f not considered; parentheses prevent argument-dependent lookup
}

end example]

Для каждого типа аргумента T в вызове функции существует набор из нуля или более associated namespaces и набор из нуля или более, associated classes которые следует учитывать. Наборы пространств имен и классов полностью определяются типами аргументов функции (и пространством имен любого аргумента шаблона шаблона). Имена Typedef, using-declarations используемые для указания типов, не участвуют в этом наборе. Наборы пространств имен и классов определяются следующим образом:

  • Если T это фундаментальный тип, связанные с ним наборы пространств имен и классов пусты.

  • Если T это тип класса (включая объединения), то связанные с ним классы: сам класс; класс, членом которого он является, если таковой имеется; и его прямые и косвенные базовые классы. Связанные с ним пространства имен - это самые внутренние включающие пространства имен связанных с ним классов. Кроме того, если T это специализация шаблона класса, связанные с ней пространства имен и классы также включают: пространства имен и классы, связанные с типами аргументов шаблона, предоставленными для параметров типа шаблона (исключая параметры шаблона шаблона); пространства имен, членами которых являются любые аргументы шаблона шаблона; и классы, членами которых являются любые шаблоны-элементы, используемые в качестве аргументов шаблона шаблона. [ Note: Аргументы шаблона, не являющиеся типом, не влияют на набор связанных пространств имен. ]end note

  • Если T это тип перечисления, связанное с ним пространство имен является самым внутренним охватывающим пространством имен его объявления. Если это член класса, связанный с ним класс - это класс члена; иначе у него нет ассоциированного класса.

  • Если T это указатель U или массив U, связанные с ним пространства имен и классы - это те, с которыми связаны U.

  • Если T это тип функции, связанные с ним пространства имен и классы - это те, которые связаны с типами параметров функции и те, которые связаны с типом возвращаемого значения.

  • Если T это указатель на функцию-член класса X, связанные с ним пространства имен и классы - это те, которые связаны с типами параметров функции и типом возвращаемого значения, вместе с теми, которые связаны с X.

  • Если T это указатель на член данных класса X, связанные с ним пространства имен и классы - это те, которые связаны с типом члена вместе с теми, которые связаны с X.

Если связанное пространство имен - это inline namespaceпространство имен, в которое оно входит, также включается в набор. Если связанное пространство имен непосредственно содержит встроенные пространства имен, эти встроенные пространства имен также включаются в набор. Кроме того, если аргумент является именем или адресом набора перегруженных функций и / или шаблонов функций, связанные с ним классы и пространства имен представляют собой объединение классов и пространств имен, связанных с каждым из членов набора, т. Е. Связанных классов и пространств имен. с типами параметров и возвращаемым типом. Кроме того, если вышеупомянутый набор перегруженных функций назван с template-id, связанные с ним классы и пространства имен также включают классы и пространства имен этого типа template-arguments и его шаблона template-arguments.

Пусть X будет набором поиска, созданным, unqualified lookup и пусть Y будет набором поиска, созданным поиском, зависимым от аргументов (определенным следующим образом). Если X содержит

  • объявление члена класса или

  • объявление функции блочной области, которое не является using-declaration, или

  • объявление, которое не является ни функцией, ни шаблоном функции

то Y пусто. В противном случае Y набор объявлений находится в пространствах имен, связанных с типами аргументов, как описано ниже. Набор объявлений, найденный при поиске имени, представляет собой объединение X и Y. [ Note: Пространства имен и классы, связанные с типами аргументов, могут включать пространства имен и классы, уже учтенные обычным неквалифицированным поиском. ] [ end noteExample:

namespace NS {
  class T { };
  void f(T);
  void g(T, int);
}
NS::T parm;
void g(NS::T, float);
int main() {
  f(parm);                      // OK: calls NS​::​f
  extern void g(NS::T, float);
  g(parm, 1);                   // OK: calls g(NS​::​T, float)
}

end example]

При рассмотрении связанного пространства имен поиск такой же, как поиск, выполняемый, когда связанное пространство имен используется в качестве квалификатора ([namespace.qual]), за исключением того, что:

  • Любые using-directives элементы в связанном пространстве имен игнорируются.

  • Любые дружественные функции в области видимости пространства имен или шаблоны дружественных функций, объявленные в связанных классах, видны в их соответствующих пространствах имен, даже если они не видны во время обычного поиска ([class.friend]).

  • Все имена, кроме (возможно, перегруженных) функций и шаблонов функций, игнорируются.

6.4.3 Qualified name lookup [basic.lookup.qual]

На имя класса или члена пространства имен или перечислителя можно ссылаться после ​::​ применения оператора разрешения области ([expr.prim]) к объекту, nested-name-specifierкоторый обозначает его класс, пространство имен или перечисление. Если перед ​::​ оператором разрешения области в a nested-name-specifierне стоит decltype-specifier, поиск предшествующего имени ​::​ учитывает только пространства имен, типы и шаблоны, специализацией которых являются типы. Если найденное имя не обозначает пространство имен или класс, перечисление или зависимый тип, программа имеет неправильный формат. [Example:

class A {
public:
  static int n;
};
int main() {
  int A;
  A::n = 42;        // OK
  A b;              // ill-formed: A does not name a type
}

end example]

[ Note: Множественные уточненные имена, например,, N1​::​N2​::​N3​::​nмогут использоваться для обозначения членов вложенных классов ([class.nest]) или членов вложенных пространств имен. ] end note

В объявлении, в котором declarator-idесть a qualified-id, имена, использованные до qualified-id объявления, ищутся в определяющей области пространства имен; имена, следующие за qualified-id, ищутся в области класса или пространства имен члена. [Example:

class X { };
class C {
  class X { };
  static const int number = 50;
  static X arr[number];
};
X C::arr[number];   // ill-formed:
                    // equivalent to ​::​X C​::​arr[C​::​number];
                    // and not to C​::​X C​::​arr[C​::​number];

end example]

Имя с префиксом унарного оператора области видимости ​::​ ([expr.prim]) ищется в глобальной области видимости в той единице перевода, в которой оно используется. Имя должно быть объявлено в области глобального пространства имен или должно быть именем, объявление которого видно в глобальной области видимости из-за using-directive([namespace.qual]). Использование ​::​ позволяет ссылаться на глобальное имя, даже если его идентификатор был hidden.

Имя с префиксом a nested-name-specifier, обозначающее тип перечисления, должно представлять собой элемент enumerator этого перечисления.

Если a pseudo-destructor-name([expr.pseudo]) содержит a nested-name-specifier, type-names ищутся типы в области, обозначенной nested-name-specifier. Аналогично в qualified-idформе:

nested-name-specifieropt class-name :: ~ class-name

второй class-nameищется в той же области, что и первый. [Example:

struct C {
  typedef int I;
};
typedef int I1, I2;
extern int* p;
extern int* q;
p->C::I::~I();      // I is looked up in the scope of C
q->I1::~I2();       // I2 is looked up in the scope of the postfix-expression

struct A {
  ~A();
};
typedef A AB;
int main() {
  AB* p;
  p->AB::~AB();     // explicitly calls the destructor for A
}

end example] [ Note: [basic.lookup.classref] Описывает , как имя подстановки после того , как протекает . и -> операторов. ] end note

6.4.3.1 Class members [class.qual]

Если nested-name-specifierиз a qualified-id назначает класс, имя, указанное после, nested-name-specifierищется в области действия class ([class.member.lookup]), за исключением случаев, перечисленных ниже. Имя должно представлять один или несколько членов этого класса или одного из его базовых классов (пункт [class.derived]). [К Note: члену класса можно обратиться с помощью a qualified-idв любой точке его потенциальной области видимости ([basic.scope.class]). ] Исключения из приведенного выше правила поиска имен следующие: end note

В поиске, в котором имена функций не игнорируются,34 а nested-name-specifierкласс назначает C:

вместо этого считается, что имя является именем конструктора класса C. [ Note: Например, конструктор не является приемлемым результатом поиска, elaborated-type-specifierпоэтому конструктор не будет использоваться вместо введенного имени класса. ] Такое имя конструктора должно использоваться только в объявлении, которое называет конструктор, или в . [ end notedeclarator-idusing-declarationExample:

struct A { A(); };
struct B: public A { B(); };

A::A() { }
B::B() { }

B::A ba;            // object of type A
A::A a;             // error, A​::​A is not a type name
struct A::A a2;     // object of type A

end example]

Имя члена класса, скрытое именем во вложенной декларативной области или именем члена производного класса, все еще можно найти, если оно уточняется именем его класса, за которым следует ​::​ оператор.

Поисковые запросы, в которых имена функций игнорируются, включают имена, содержащиеся в a nested-name-specifier, an elaborated-type-specifierили a base-specifier.

6.4.3.2 Namespace members [namespace.qual]

Если nested-name-specifiera qualified-id назначает пространство имен (включая случай, когда nested-name-specifieris ​::​, т. Е. Назначает глобальное пространство имен), имя, указанное после a, ищется nested-name-specifierв области пространства имен. Имена в a template-argumentили a template-idищутся в контексте, в котором postfix-expressionвстречается целое .

Для пространства имен X и имени mнабор поиска с указанием пространства имен S(X,m) определяется следующим образом: Пусть S(X,m) будет набором всех объявлений m in X и inline namespace set of X. Если S(X,m) не пусто, то S(X,m) есть S(X,m); в противном случае S(X,m) - это объединение S(Ni,m) всех пространств имен, Ni назначенных using-directives in, X и его встроенного набора пространств имен.

Задано X​::​m (где X - объявленное пользователем пространство имен) или задано ​::​m (где X - глобальное пространство имен), если S(X,m) это пустой набор, программа плохо сформирована. В противном случае, если S(X,m) имеет ровно один член или если контекст ссылки является a using-declaration, S(X,m) является требуемым набором объявлений m. В противном случае, если использование m не позволяет выбрать уникальное объявление S(X,m), программа имеет неправильный формат. [Example:

int x;
namespace Y {
  void f(float);
  void h(int);
}

namespace Z {
  void h(double);
}

namespace A {
  using namespace Y;
  void f(int);
  void g(int);
  int i;
}

namespace B {
  using namespace Z;
  void f(char);
  int i;
}

namespace AB {
  using namespace A;
  using namespace B;
  void g();
}

void h()
{
  AB::g();      // g is declared directly in AB, therefore S is { AB​::​g() } and AB​::​g() is chosen

  AB::f(1);     // f is not declared directly in AB so the rules are applied recursively to A and B;
                // namespace Y is not searched and Y​::​f(float) is not considered;
                // S is {A::f(int),B::f(char)} and overload resolution chooses A​::​f(int)

  AB::f('c');   // as above but resolution chooses B​::​f(char)

  AB::x++;      // x is not declared directly in AB, and is not declared in A or B, so the rules
                // are applied recursively to Y and Z, S is { } so the program is ill-formed

  AB::i++;      // i is not declared directly in AB so the rules are applied recursively to A and B,
                // S is {A::i,B::i} so the use is ambiguous and the program is ill-formed

  AB::h(16.8);  // h is not declared directly in AB and not declared directly in A or B so the rules
                // are applied recursively to Y and Z, S is {Y::h(int),Z::h(double)} and
                // overload resolution chooses Z​::​h(double)
}

end example]

[ Note: Одно и то же объявление, найденное более одного раза, не является двусмысленностью (потому что это все еще уникальное объявление). [Example:

namespace A {
  int a;
}

namespace B {
  using namespace A;
}

namespace C {
  using namespace A;
}

namespace BC {
  using namespace B;
  using namespace C;
}

void f()
{
  BC::a++;          // OK: S is {A::a,A::a}
}

namespace D {
  using A::a;
}

namespace BD {
  using namespace B;
  using namespace D;
}

void g()
{
  BD::a++;          // OK: S is {A::a,A::a}
}

end example] ]end note

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

namespace B {
  int b;
}

namespace A {
  using namespace B;
  int a;
}

namespace B {
  using namespace A;
}

void f()
{
  A::a++;           // OK: a declared directly in A, S is { A​::​a }
  B::a++;           // OK: both A and B searched (once), S is { A​::​a }
  A::b++;           // OK: both A and B searched (once), S is { B​::​b }
  B::b++;           // OK: b declared directly in B, S is { B​::​b }
}

end example]

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

namespace A {
  struct x { };
  int x;
  int y;
}

namespace B {
  struct y { };
}

namespace C {
  using namespace A;
  using namespace B;
  int i = C::x;     // OK, A​::​x (of type int)
  int j = C::y;     // ambiguous, A​::​y or B​::​y
}

end example]

В объявлении для члена пространства имен, в котором declarator-idесть qualified-id, при условии, что qualified-idдля члена пространства имен имеет форму

nested-name-specifier unqualified-id

unqualified-idбудет называть элемент пространства имен обозначены той nested-name-specifier или элемент из inline namespace set этого пространства имен. [Example:

namespace A {
  namespace B {
    void f1(int);
  }
  using namespace B;
}
void A::f1(int){ }  // ill-formed, f1 is not a member of A

end example] Однако в таких объявлениях членов пространства имен объект nested-name-specifierможет using-directives неявно предоставить начальную часть nested-name-specifier. [Example:

namespace A {
  namespace B {
    void f1(int);
  }
}

namespace C {
  namespace D {
    void f1(int);
  }
}

using namespace A;
using namespace C::D;
void B::f1(int){ }  // OK, defines A​::​B​::​f1(int)

end example]

6.4.4 Elaborated type specifiers [basic.lookup.elab]

elaborated-type-specifierМожет быть использовано для обозначения предварительно объявленных class-nameили enum-nameхотя имя было hidden в заявлении не-типа.

Если elaborated-type-specifierнет nested-name-specifier, и если он не elaborated-type-specifierуказан в декларации следующей формы:

class-key attribute-specifier-seqopt identifier ;

identifierищется в соответствии [basic.lookup.unqual] но игнорируя любые имена не типа , которые были объявлены. Если elaborated-type-specifierвводится enum ключевым словом, и этот поиск не находит ранее объявленного type-name, то elaborated-type-specifier это неправильно сформировано. Если elaborated-type-specifierвводится с помощью, class-keyи этот поиск не находит ранее объявленного type-name, или если elaborated-type-specifierпоявляется в объявлении с формой:

class-key attribute-specifier-seqopt identifier ;

elaborated-type-specifierявляется свидетельством того, что вводит , class-nameкак описано в [basic.scope.pdecl].

Если elaborated-type-specifierесть nested-name-specifier, выполняется поиск квалифицированного имени, как описано в разделе [basic.lookup.qual], но игнорируя любые объявленные не-типовые имена. Если поиск по имени не находит ранее объявленного type-name, elaborated-type-specifier значит, неправильно сформирован. [Example:

struct Node {
  struct Node* Next;            // OK: Refers to Node at global scope
  struct Data* Data;            // OK: Declares type Data
                                // at global scope and member Data
};

struct Data {
  struct Node* Node;            // OK: Refers to Node at global scope
  friend struct ::Glob;         // error: Glob is not declared, cannot introduce a qualified type ([dcl.type.elab])
  friend struct Glob;           // OK: Refers to (as yet) undeclared Glob at global scope.
  /* ... */
};

struct Base {
  struct Data;                  // OK: Declares nested Data
  struct ::Data*     thatData;  // OK: Refers to ​::​Data
  struct Base::Data* thisData;  // OK: Refers to nested Data
  friend class ::Data;          // OK: global Data is a friend
  friend class Data;            // OK: nested Data is a friend
  struct Data { /* ... */ };    // Defines nested Data
};

struct Data;                    // OK: Redeclares Data at global scope
struct ::Data;                  // error: cannot introduce a qualified type ([dcl.type.elab])
struct Base::Data;              // error: cannot introduce a qualified type ([dcl.type.elab])
struct Base::Datum;             // error: Datum undefined
struct Base::Data* pBase;       // OK: refers to nested Data

end example]

6.4.5 Class member access [basic.lookup.classref]

В class member access выражении, если за токеном . или -> сразу следует символ, за которым identifier следует символ <, необходимо найти идентификатор, чтобы определить, < является ли это началом списка аргументов шаблона ([temp.names]) или оператором «меньше». Идентификатор сначала ищется в классе выражения объекта. Если идентификатор не найден, он затем ищется в контексте всего postfix-expressionи должен дать имя шаблону класса.

Если id-expressionin a class member access - это unqualified-id, а тип выражения объекта относится к типу класса C, unqualified-idищется в области действия класса C. Для pseudo-destructor call, то unqualified-idищется в контексте полной postfix-expression.

Если unqualified-idесть , то ищется в контексте всего . Если тип объектного выражения относится к типу класса , он также ищется в области действия класса . По крайней мере, один из поисков должен найти имя, которое относится к . [ ~type-nametype-namepostfix-expression T Ctype-name C cv TExample:

struct A { };

struct B {
  struct A { };
  void f(::A* a);
};

void B::f(::A* a) {
  a->~A();                      // OK: lookup in *a finds the injected-class-name
}

end example]

Если id-expressionдоступ для члена класса имеет qualified-idформу

class-name-or-namespace-name::...

class-name-or-namespace-name следуя . или -> оператор сначала ищется в классе выражения объекта и имя, если он найден, используется. В противном случае он ищется в контексте всего postfix-expression. [ Note: См. [basic.lookup.qual], Где описан поиск имени ранее ​::​, при котором будет найден только тип или имя пространства имен. ] end note

Если qualified-idимеет вид

::class-name-or-namespace-name::...

class-name-or-namespace-name ищется в глобальном масштабе в виде class-nameили namespace-name.

Если nested-name-specifierсодержит a simple-template-id, имена в нем template-arguments ищутся в контексте, в котором postfix-expressionвстречается все.

Если id-expressionэто a conversion-function-id, его conversion-type-id сначала ищут в классе выражения объекта, и имя, если оно найдено, используется. В противном случае он ищется в контексте всего postfix-expression. В каждом из этих поисков учитываются только имена, обозначающие типы или шаблоны, специализацией которых являются типы. [Example:

struct A { };
namespace N {
  struct A {
    void g() { }
    template <class T> operator T();
  };
}

int main() {
  N::A a;
  a.operator A();               // calls N​::​A​::​operator N​::​A
}

end example]

6.4.6 Using-directives and namespace aliases [basic.lookup.udir]

В using-directiveor namespace-alias-definition, во время поиска namespace-nameили для имени в nested-name-specifier пространстве имен учитываются только имена.