На имя класса или члена пространства имен или перечислителя можно ссылаться после :: применения оператора разрешения области ([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
Если nested-name-specifierиз a qualified-id назначает класс, имя, указанное после, nested-name-specifierищется в области действия class ([class.member.lookup]), за исключением случаев, перечисленных ниже. Имя должно представлять один или несколько членов этого класса или одного из его базовых классов (пункт[class.derived]). [К Note: члену класса можно обратиться с помощью a qualified-idв любой точке его потенциальной области видимости ([basic.scope.class]). ] Исключения из приведенного выше правила поиска имен следующие: — end note
поиск деструктора такой, как указано в[basic.lookup.qual];
a conversion-type-idиз a conversion-function-idищется таким же образом, как и conversion-type-idв доступе к члену класса (см.[basic.lookup.classref]);
имена в a template-argumentиз a template-idищутся в контексте, в котором postfix-expressionпроисходит целое .
поиск имени, указанного в a, using-declarationтакже находит имена классов или перечисленийhidden в той же области.
В поиске, в котором имена функций не игнорируются,34 а nested-name-specifierкласс назначаетC:
если имя, указанное после nested-name-specifier, при поискеC, является внедренным именем классаC (Пункт[class]), или
в using-declaratorиз , using-declarationчто это member-declaration, если имя , указанное после nested-name-specifierтакой же , как identifierи в simple-template-id«х template-nameв последнем компоненте из nested-name-specifier,
вместо этого считается, что имя является именем конструктора классаC. [ Note: Например, конструктор не является приемлемым результатом поиска, elaborated-type-specifierпоэтому конструктор не будет использоваться вместо введенного имени класса. ] Такое имя конструктора должно использоваться только в объявлении, которое называет конструктор, или в . [ — end note declarator-idusing-declaration Example:
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.
Если 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 ]