[class.member.lookup] (original) (raw)
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 M from a program point Pis a single search in X for M from Punless 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 M is a conversion-function-id or if the single search would find nothing.
— _end note_]
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.
S(N,C) is calculated as follows:
The declaration set is the result of a single search in the scope of C for Nfrom immediately after the class-specifier of Cif 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 Nor the resulting declaration set is empty), S(N,C) is initially empty.
Calculate the lookup set for Nin each direct non-dependent ([temp.dep.type]) base class subobject , and merge each such lookup set in turn into S(N,C).
[Note 2:
If C is incomplete, only base classes whose base-specifier appears before Pare considered.
If C 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 S(N,C):
- If each of the subobject members of is a base class subobject of at least one of the subobject members of S(N,C), or if 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 , or ifS(N,C) is empty, the new S(N,C) is a copy of . - Otherwise, if the declaration sets of 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. - Otherwise, the new S(N,C) 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 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 Min a complete-class context ([class.mem]) of T, the program is ill-formed, no diagnostic required.
[Example 1: struct A { int x; }; struct B { float x; }; struct C: public A, public B { }; struct D: public virtual C { }; struct E: public virtual C { char x; }; struct F: public D, public E { }; int main() { F f; f.x = 0; }
S(x,F) is unambiguous because the A and B base class subobjects of D are also base class subobjects of E, soS(x,D) is discarded in the first merge step.
— _end example_]
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 tonly 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 M ([temp.over]).
— _end note_]
[Note 4:
A static member, a nested type or an enumerator defined in a base classT 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++; pd->s++; int i = pd->e; pd->a++; } — _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 Ware 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++; f(); y++; 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; V* pv = &d; } — _end example_]
[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(); f(0); f(0.0); int B1::* mpB1 = &D::i; int D::* mpD = &D::i; } }; — _end example_]