[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):

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_]