using-declaration: using using-declarator-list ;
using-declarator-list: using-declarator ...opt using-declarator-list , using-declarator ...opt
using-declarator: typenameopt nested-name-specifier unqualified-id
Каждый using-declaratorв a using-declaration98 вводит набор объявлений в декларативную область, в которой using-declarationпоявляется. Набор объявлений, представленных объектом, using-declaratorнаходится путем выполнения поиска по квалифицированному имени ([basic.lookup.qual],[class.member.lookup]) для имени в using-declarator, за исключением функций, которые скрыты, как описано ниже. Если using-declaratorне называет конструктор, unqualified-idобъявляется в декларативной области, в которой using-declarationпоявляется как синоним для каждого объявления, представленного using-declarator. [ Note: Так объявляется только указанное имя; указание имени перечисления в a using-declaration не объявляет его перечислители в using-declarationдекларативной области. ] Если именует конструктор, он объявляет, что класс - это набор объявлений конструктора, представленных от назначенного базового класса. — end note using-declaratorinherits using-declarator
Every using-declaration- это a declarationи a, member-declarationпоэтому их можно использовать в определении класса. [ Example:
struct B { void f(char); void g(char); enum E { e }; union { int x; }; }; struct D : B { using B::f; void f(int) { f('c'); } // calls B::f(char) void g(int) { g('c'); } // recursively calls D::g(int) };
— end example ]
В using-declarationиспользуются в качестве member-declaration, каждый using-declarator«s nested-name-specifier будет называть базовый класс определяемым класса. Если a using-declaratorназывает конструктор, он nested-name-specifierдолжен называть прямой базовый класс определяемого класса. [ Example:
template <typename... bases>
struct X : bases... {
using bases::g...;
};
X<B, D> x; // OK: B::g and D::g introduced
— end example ] [ Example:
class C { int g(); }; class D2 : public B { using B::f; // OK: B is a base of D2 using B::e; // OK: e is an enumerator of base B using B::x; // OK: x is a union member of base B using C::g; // error: C isn't a base of D2 };
— end example ]
[ Note: Поскольку деструкторы не имеют имен, a using-declarationне может ссылаться на деструктор базового класса. Поскольку специализации шаблонов членов для функций преобразования не могут быть найдены с помощью поиска по имени, они не учитываются, когда a using-declarationуказывает функцию преобразования ([temp.mem]). ] Если конструктор или оператор присваивания, перенесенный из базового класса в производный класс, имеет сигнатуру конструктора копирования / перемещения или оператора присваивания для производного класса ( ), сам по себе не подавляет неявное объявление члена производного класса; член базового класса скрыт или переопределен неявно объявленным конструктором копирования / перемещения или оператором присваивания производного класса, как описано ниже. — end note [class.copy]using-declaration
A using-declarationне должен называть a template-id. [ Example:
struct A { template <class T> void f(T); template <class T> struct X { }; }; struct B : A { using A::f<double>; // ill-formed using A::X<int>; // ill-formed };
— end example ]
Имя using-declarationчлена класса должно быть member-declaration. [ Example:
struct X { int i; static int s; }; void f() { using X::i; // error: X::i is a class member and this is not a member declaration. using X::s; // error: X::s is a class member and this is not a member declaration. }
— end example ]
На члены, объявленные a, using-declarationможно ссылаться с помощью явной квалификации, как и на другие имена членов ([namespace.qual]). [ Example:
void f(); namespace A { void g(); } namespace X { using ::f; // global f using A::g; // A's g } void h() { X::f(); // calls ::f X::g(); // calls A::g }
— end example ]
A using-declaration- это a declarationи поэтому может использоваться повторно там, где (и только когда) разрешено несколько объявлений. [ Example:
namespace A { int i; } namespace A1 { using A::i, A::i; // OK: double declaration } struct B { int i; }; struct X : B { using B::i, B::i; // error: double member declaration };
— end example ]
[ Note: Для элемента, using-declaration чьи nested-name-specifierимена являются пространством имен, члены, добавленные к пространству имен после элемента using-declaration , не входят в набор представленных объявлений, поэтому они не учитываются при использовании имени. Таким образом, дополнительные перегрузки, добавленные после using-declaration, игнорируются, но учитываются аргументы функции по умолчанию ([dcl.fct.default]), аргументы шаблона по умолчанию ([temp.param]) и специализации шаблона ([temp.class.spec], [temp.expl.spec]). ] [ — end note Example:
namespace A { void f(int); } using A::f; // f is a synonym for A::f; that is, for A::f(int). namespace A { void f(char); } void foo() { f('a'); // calls f(int), even though f(char) exists. } void bar() { using A::f; // f is a synonym for A::f; that is, for A::f(int) and A::f(char). f('a'); // calls f(char) }
— end example ]
[ Note: Частичные специализации шаблонов классов можно найти путем поиска основного шаблона класса и последующего рассмотрения всех частичных специализаций этого шаблона. Если a using-declarationназывает шаблон класса, частичные специализации, введенные после using-declaration, фактически видны, потому что первичный шаблон является видимым ([temp.class.spec]). ] — end note
Поскольку a using-declarationявляется объявлением, ограничения на одноименное объявление в нем declarative region также применяются к using-declarations. [ Example:
namespace A { int x; } namespace B { int i; struct g { }; struct x { }; void f(int); void f(double); void g(char); // OK: hides struct g } void func() { int i; using B::i; // error: i declared twice void f(char); using B::f; // OK: each f is a function f(3.5); // calls B::f(double) using B::g; g('a'); // calls B::g(char) struct g g1; // g1 has class type B::g using B::x; using A::x; // OK: hides struct B::x x = 99; // assigns to A::x struct x x1; // x1 has class type B::x }
— end example ]
Если объявление функции в области пространства имен или области блока имеет то же имя и то же самое,parameter-type-list что и функция, представленная с помощью a using-declaration, и объявления не объявляют ту же функцию, программа имеет неправильный формат. Если объявление шаблона функции в области пространства имен имеет то же имя, список типов параметров, возвращаемый тип и список параметров шаблона, что и шаблон функции, введенный с помощью a using-declaration, программа имеет неправильный формат. [ Note: Двое using-declarations могут вводить функции с одним и тем же именем и одним и тем же списком типов параметров. Если для вызова неквалифицированного имени функции разрешение перегрузки функции выбирает функции, введенные таким образом using-declarations, вызов функции имеет неправильный формат. [ Example:
namespace B { void f(int); void f(double); } namespace C { void f(int); void f(double); void f(char); } void h() { using B::f; // B::f(int) and B::f(double) using C::f; // C::f(int), C::f(double), and C::f(char) f('h'); // calls C::f(char) f(1); // error: ambiguous: B::f(int) or C::f(int)? void f(int); // error: f(int) conflicts with C::f(int) and B::f(int) }
— end example ] ] — end note
Когда a using-declaratorпереносит объявления из базового класса в производный класс, функции-члены и шаблоны функций-членов в производном классе переопределяют и / или скрывают функции-члены и шаблоны функций-членов с тем же именем parameter-type-list,, cv-qualification и ref-qualifier(если есть) в базовый класс (а не конфликтующий). Такие скрытые или переопределенные объявления исключаются из набора объявлений, введенных платформой using-declarator. [ Example:
struct B { virtual void f(int); virtual void f(char); void g(int); void h(int); }; struct D : B { using B::f; void f(int); // OK: D::f(int) overrides B::f(int); using B::g; void g(char); // OK using B::h; void h(int); // OK: D::h(int) hides B::h(int) }; void k(D* p) { p->f(1); // calls D::f(int) p->f('a'); // calls B::f(char) p->g(1); // calls B::g(int) p->g('a'); // calls D::g(char) } struct B1 { B1(int); }; struct B2 { B2(int); }; struct D1 : B1, B2 { using B1::B1; using B2::B2; }; D1 d1(0); // ill-formed: ambiguous struct D2 : B1, B2 { using B1::B1; using B2::B2; D2(int); // OK: D2::D2(int) hides B1::B1(int) and B2::B2(int) }; D2 d2(0); // calls D2::D2(int)
— end example ]
В целях разрешения перегрузки функции, которые вводятся using-declarationв производный класс, обрабатываются так, как если бы они были членами производного класса. В частности, неявныйthis параметр следует рассматривать как указатель на производный класс, а не на базовый класс. Это не влияет на тип функции, и во всех других отношениях функция остается членом базового класса. Кроме того, конструкторы, которые вводятся через А using-declaration , рассматриваются как если бы они были конструкторами производного класса при поиске конструкторов производного класса ([class.qual]) или формирования набора кандидатов перегрузки ([over.match.ctor],[over.match.copy],[over.match.list]). Если такой конструктор выбран для выполнения инициализации объекта типа класса, все подобъекты, кроме базового класса, из которого произошел конструктор, инициализируются неявно ([class.inhctor.init]).
В a using-declarator, который не называет конструктор, все члены набора введенных объявлений должны быть доступны. В элементе, using-declaratorкоторый называет конструктор, проверка доступа не выполняется. В частности, если производный класс использует using-declaratorдля доступа к члену базового класса, имя члена должно быть доступно. Если имя совпадает с именем перегруженной функции-члена, тогда все указанные функции должны быть доступны. Члены базового класса, упомянутые a, using-declaratorдолжны быть видимы в области видимости по крайней мере одного из прямых базовых классов класса, в котором using-declaratorуказан.
[ Note: Поскольку a using-declaratorобозначает член базового класса (а не подобъект члена или функцию члена подобъекта базового класса), a using-declaratorнельзя использовать для разрешения унаследованных двусмысленностей членов. [ Example:
struct A { int x(); };
struct B : A { };
struct C : A {
using A::x;
int x(int);
};
struct D : B, C {
using C::x;
int x(double);
};
int f(D* d) {
return d->x(); // error: overload resolution selects A::x, but A is an ambiguous base class
}
— end example ] ] — end note
Синоним, созданный a, using-declarationимеет обычную доступность для a member-declaration. Объект, using-declaratorкоторый называет конструктор, не создает синоним; вместо этого дополнительные конструкторы доступны, если они будут доступны при использовании для создания объекта соответствующего базового класса, а доступность using-declarationигнорируется. [ Example:
class A { private: void f(char); public: void f(int); protected: void g(); }; class B : public A { using A::f; // error: A::f(char) is inaccessible public: using A::g; // B::g is a public synonym for A::g };
— end example ]
Если a using-declaratorиспользует ключевое словоtypename и указывает зависимое имя ([temp.dep]), имя, введенное с помощью using-declaration, обрабатывается как typedef-name.
A using-declarationс более чем одним using-declaratorэквивалентно соответствующей последовательности using-declarations с одним using-declaratorкаждым.