19 KiB
[namespace.udecl]
9 Declarations [dcl]
9.10 The using declaration [namespace.udecl]
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
The component names of a using-declarator are those of its nested-name-specifier and unqualified-id.
Each using-declarator in a using-declaration84 names the set of declarations found by lookup ([basic.lookup.qual]) for the using-declarator, except that class and enumeration declarations that would be discarded are merely ignored when checking for ambiguity ([basic.lookup]), conversion function templates with a dependent return type are ignored, and certain functions are hidden as described below.
If the terminal name of the using-declarator is dependent ([temp.dep.type]), the using-declarator is considered to name a constructor if and only if the nested-name-specifier has a terminal name that is the same as the unqualified-id.
If the lookup in any instantiation finds that a using-declarator that is not considered to name a constructor does do so, or that a using-declarator that is considered to name a constructor does not, the program is ill-formed.
If the using-declarator names a constructor, it declares that the class inherits the named set of constructor declarations from the nominated base class.
[Note 1:
Otherwise, the unqualified-id in the using-declarator is bound to the using-declarator, which is replaced during name lookup with the declarations it names ([basic.lookup]).
If such a declaration is of an enumeration, the names of its enumerators are not bound.
For the keyword typename, see [temp.res].
â end note]
In a using-declaration used as amember-declaration, each using-declarator shall either name an enumerator or have a nested-name-specifier naming a base class of the current class ([expr.prim.this]).
[Example 1: enum class button { up, down };struct S {using button::up; button b = up; // OK}; â end example]
If ausing-declarator names a constructor, its nested-name-specifier shall name a direct base class of the current class.
If the immediate (class) scope is associated with a class template, it shall derive from the specified base class or have at least one dependent base class.
[Example 2: struct B {void f(char); enum E { e }; union { int x; };};
struct C {int f();};
struct D : B {using B::f; // OK, B is a base of Dusing B::e; // OK, e is an enumerator of base Busing B::x; // OK, x is a union member of base Busing C::f; // error: C isn't a base of Dvoid f(int) { f('c'); } // calls B::f(char)void g(int) { g('c'); } // recursively calls D::g(int)};template <typename... bases>struct X : bases... {using bases::f...;}; X<B, C> x; // OK, B::f and C::f named â end example]
[Note 2:
Since destructors do not have names, ausing-declaration cannot refer to a destructor for a base class.
â end note]
If a constructor or assignment operator brought from a base class into a derived class has the signature of a copy/move constructor or assignment operator for the derived class ([class.copy.ctor], [class.copy.assign]), the using-declaration does not by itself suppress the implicit declaration of the derived class member; the member from the base class is hidden or overridden by the implicitly-declared copy/move constructor or assignment operator of the derived class, as described below.
A using-declaration shall not name a template-id.
[Example 3: struct A {template void f(T); template struct X { };};struct B : A {using A::f; // errorusing A::X; // error}; â end example]
A using-declaration shall not name a namespace.
A using-declaration that names a class member other than an enumerator shall be amember-declaration.
[Example 4: 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]
If a declaration is named by two using-declarators that inhabit the same class scope, the program is ill-formed.
[Example 5: struct C {int i;};
struct D1 : C { };struct D2 : C { };
struct D3 : D1, D2 {using D1::i; // OK, equivalent to using C::iusing D1::i; // error: duplicateusing D2::i; // error: duplicate, also names C::i}; â end example]
[Note 3:
A using-declarator whose nested-name-specifier names a namespace does not name declarations added to the namespace after it.
Thus, additional overloads added after the using-declaration are ignored, but default function arguments ([dcl.fct.default]), default template arguments ([temp.param]), and template specializations ([temp.spec.partial], [temp.expl.spec]) are considered.
â end note]
[Example 6: 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]
If a declaration named by a using-declaration that inhabits the target scope of another declaration B potentially conflicts with it ([basic.scope.scope]), and either is reachable from the other, the program is ill-formed unless B is name-independent and the using-declaration precedes B.
[Example 7: int _;void f() {int ; // B _ = 0; using ::; // error: using-declaration does not precede B} â end example]
If two declarations named by using-declarations that inhabit the same scope potentially conflict, either is reachable from the other, and they do not both declare functions or function templates, the program is ill-formed.
[Note 4:
Overload resolution possibly cannot distinguish between conflicting function declarations.
â end note]
[Example 8: namespace A {int x; int f(int); int g; void h();}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: conflictsvoid f(char); using B::f; // OK, each f is a functionusing A::f; // OK, but interferes with B::f(int) f(1); // error: ambiguousstatic_cast<int(*)(int)>(f)(1); // OK, calls A::f f(3.5); // calls B::f(double)using B::g; g('a'); // calls B::g(char)struct g g1; // g1 has class type B::gusing A::g; // error: conflicts with B::gvoid h(); using A::h; // error: conflictsusing B::x; using A::x; // OK, hides struct B::xusing A::x; // OK, does not conflict with previous using A::x x = 99; // assigns to A::xstruct x x1; // x1 has class type B::x} â end example]
The set of declarations named by a using-declarator that inhabits a class C does not include member functions and member function templates of a base class that correspond to (and thus would conflict with) a declaration of a function or function template in C.
[Example 9: 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); // OKusing 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); // error: ambiguousstruct 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]
[Note 5:
For the purpose of forming a set of candidates during overload resolution, the functions named by a using-declaration in a derived class are treated as though they were direct members of the derived class.
In particular, the implicit object parameter is treated as if it were a reference to the derived class rather than to the base class ([over.match.funcs]).
This has no effect on the type of the function, and in all other respects the function remains part of the base class.
â end note]
Constructors that are named by a using-declaration are treated as though they were constructors of the derived class when looking up the constructors of the derived class ([class.qual]) or forming a set of overload candidates ([over.match.ctor], [over.match.copy], [over.match.list]).
[Note 6:
If such a constructor is selected to perform the initialization of an object of class type, all subobjects other than the base class from which the constructor originated are implicitly initialized ([class.inhctor.init]).
A constructor of a derived class is sometimes preferred to a constructor of a base class if they would otherwise be ambiguous ([over.match.best]).
â end note]
In a using-declarator that does not name a constructor, every declaration named shall be accessible.
In a using-declarator that names a constructor, no access check is performed.
[Note 7:
Because a using-declarator designates a base class member (and not a member subobject or a member function of a base class subobject), a using-declarator cannot be used to resolve inherited member ambiguities.
[Example 10: 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 has the usual accessibility for a member-declaration.
Base-class constructors considered because of a using-declarator are accessible if they would be accessible when used to construct an object of the base class; the accessibility of the using-declaration is ignored.
[Example 11: 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 inaccessiblepublic:using A::g; // B::g is a public synonym for A::g}; â end example]
A using-declaration with more than oneusing-declarator is equivalent to a corresponding sequence of using-declarations with one using-declarator each.