Each using-declarator in a using-declaration88
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 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.
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]
Since destructors do not have names, a
using-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.
[Example 4: struct X {int i;
staticint 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]
[Example 5: 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
potentially conflicts with it ([basic.scope.scope]), and
either is reachable from the other, the program is ill-formed.
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.
Overload resolution possibly cannot distinguish
between conflicting function declarations.
— end note]
[Example 6: 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::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.
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.
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]).
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 8: 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]
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 9: 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]