A search in a scope X for a name M from a program point P
is a single search in X for M from P
unless X is the scope of a class or class template T, in which case the
following steps define the result of the search.
The lookup set for a name N in a class or class template C, called S(N,C),
consists of two component sets:
the declaration set, a set of members named N; and
the subobject set,
a set of subobjects where declarations of these members were found
(possibly via using-declarations).
In the declaration set, type declarations (including injected-class-names)
are replaced by the types they designate.
The declaration set is the result of
a single search in the scope of C for N
from immediately after the class-specifier of C
if P is in a complete-class context of C or
from P otherwise.
If the resulting declaration set is not empty, the subobject set
contains C itself, and calculation is complete.
Otherwise (i.e., C does not contain a declaration of N
or the resulting declaration set is empty), S(N,C) is initially empty.
Calculate the lookup set for N
in each direct non-dependent ([temp.dep.type]) base class subobject Bi, and
merge each such lookup set S(N,Bi) in turn into S(N,C).
If each of the subobject members of S(N,Bi) is a base class
subobject of at least one of the subobject members of S(N,C), or if
S(N,Bi) is empty, S(N,C) is unchanged and the merge is complete.
Conversely, if each of the subobject members of S(N,C) is a base class
subobject of at least one of the subobject members of S(N,Bi), or if
S(N,C) is empty, the new S(N,C) is a copy of S(N,Bi).
Otherwise, if the declaration sets of S(N,Bi) and S(N,C)
differ, the merge is ambiguous: the new S(N,C) is a lookup set with an
invalid declaration set and the union of the subobject sets.
In
subsequent merges, an invalid declaration set is considered different
from any other.
The result of the search is the declaration set of S(M,T).
If it is an invalid set, the program is ill-formed.
If it differs from the result of a search in T for M
in a complete-class context ([class.mem]) of T,
the program is ill-formed, no diagnostic required.
[Example 1: struct A {int x; }; // S(x,A) = { { A::x }, { A } }struct B {float x; }; // S(x,B) = { { B::x }, { B } }struct C:public A, public B {}; // S(x,C) = { invalid, { A in C, B in C } }struct D:publicvirtual C {}; // S(x,D) = S(x,C)struct E:publicvirtual C {char x; }; // S(x,E) = { { E::x }, { E } }struct F:public D, public E {}; // S(x,F) = S(x,E)int main(){
F f;
f.x =0; // OK, lookup finds E::x}
S(x,F) is unambiguous because the A and B base
class subobjects of D are also base class subobjects of E, so
S(x,D) is discarded in the first merge step.
If M is a non-dependent conversion-function-id,
conversion function templates that are members of T are considered.
For each such template F, the lookup set S(t,T) is constructed,
considering a function template declaration to have the name t
only if it corresponds to a declaration of F ([basic.scope.scope]).
The members of the declaration set of each such lookup set,
which shall not be an invalid set, are included in the result.
A static member, a nested type or an enumerator defined in a base class
T can unambiguously be found even if an object has more than one
base class subobject of type T.
Two base class subobjects share
the non-static member subobjects of their common virtual base classes.
— end note]
[Example 2: struct V {int v;
};
struct A {int a;
staticint s;
enum{ e };
};
struct B : A, virtual V {};
struct C : A, virtual V {};
struct D : B, C {};
void f(D* pd){
pd->v++; // OK, only one v (virtual)
pd->s++; // OK, only one s (static)int i = pd->e; // OK, only one e (enumerator)
pd->a++; // error: ambiguous: two as in D} — end example]
When virtual base classes are used, a hidden declaration can be reached
along a path through the subobject lattice that does not pass through
the hiding declaration.
The identical use with
non-virtual base classes is an ambiguity; in that case there is no
unique instance of the name that hides all the others.
— end note]
[Example 3: struct V {int f(); int x; };
struct W {int g(); int y; };
struct B :virtual V, W {int f(); int x;
int g(); int y;
};
struct C :virtual V, W {};
struct D : B, C {void glorp(); };
As illustrated in Figure 1,
the names declared in V and the left-hand instance of W
are hidden by those in B, but the names declared in the
right-hand instance of W are not hidden at all.
An explicit or implicit conversion from a pointer to or
an expression designating an object
of a
derived class to a pointer or reference to one of its base classes shall
unambiguously refer to a unique object representing the base class.
[Example 4: struct V {};
struct A {};
struct B : A, virtual V {};
struct C : A, virtual V {};
struct D : B, C {};
void g(){
D d;
B* pb =&d;
A* pa =&d; // error: ambiguous: C's A or B's A?
V* pv =&d; // OK, only one V subobject} — end example]
Even if the result of name lookup is unambiguous, use of a name found in
multiple subobjects might still be
ambiguous ([conv.mem], [expr.ref], [class.access.base]).