6 Basics [basic]

6.5 Name lookup [basic.lookup]

6.5.2 Member name lookup [class.member.lookup]

A search in a scope X for a name N from a program point P is a single search in X for N 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.
[Note 1:
The result differs only if N is a conversion-function-id or if the single search would find nothing.
— end note]
The lookup set for N in C, called , 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.
is calculated as follows:
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), is initially empty.
Calculate the lookup set for N in each direct non-dependent ([temp.dep.type]) base class subobject , and merge each such lookup set in turn into .
[Note 2:
If T is incomplete, only base classes whose base-specifier appears before P are considered.
If T is an instantiated class, its base classes are not dependent.
— end note]
The following steps define the result of merging lookup set into the intermediate :
  • If each of the subobject members of is a base class subobject of at least one of the subobject members of , or if is empty, is unchanged and the merge is complete.
    Conversely, if each of the subobject members of is a base class subobject of at least one of the subobject members of , or if is empty, the new is a copy of .
  • Otherwise, if the declaration sets of and differ, the merge is ambiguous: the new 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.
  • Otherwise, the new is a lookup set with the shared set of declarations and the union of the subobject sets.
The result of the search is the declaration set of .
If it is an invalid set, the program is ill-formed.
If it differs from the result of a search in T for N from immediately after the class-specifier 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: public virtual C { }; // S(x,D) = S(x,C) struct E: public virtual 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 }
is unambiguous because the A and B base class subobjects of D are also base class subobjects of E, so is discarded in the first merge step.
— end example]
If N 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 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.
[Note 3:
Overload resolution will discard those that cannot convert to the type specified by N ([temp.over]).
— end note]
[Note 4:
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; static int 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]
[Note 5:
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.
This is not an ambiguity.
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(); };
virt W1 W V V W2 W B B B->W1 B->V C C C->V C->W2 D D D->B D->C
Figure 1: Name lookup  [fig:class.lookup]
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.
void D::glorp() { x++; // OK: B​::​x hides V​::​x f(); // OK: B​::​f() hides V​::​f() y++; // error: B​::​y and C's W​::​y g(); // error: B​::​g() and C's W​::​g() } — end example]
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]
[Note 6:
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]).
— end note]
[Example 5: struct B1 { void f(); static void f(int); int i; }; struct B2 { void f(double); }; struct I1: B1 { }; struct I2: B1 { }; struct D: I1, I2, B2 { using B1::f; using B2::f; void g() { f(); // Ambiguous conversion of this f(0); // Unambiguous (static) f(0.0); // Unambiguous (only one B2) int B1::* mpB1 = &D::i; // Unambiguous int D::* mpD = &D::i; // Ambiguous conversion } }; — end example]