6 Basic concepts [basic]

6.4 Name lookup [basic.lookup]

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 inX и 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]