[class.member.lookup] (original) (raw)
11 Classes [class]
Name lookup can result in an ambiguity, in which case the program is ill-formed.
The following steps define the result of name lookup for a member namef in a class scope C.
The lookup set for f in C, called , consists of two component sets: the declaration set, a set of members named f; and the subobject set, a set of subobjects where declarations of these members (possibly includingusing-declarations) were found.
In the declaration set,using-declarations are replaced by the set of designated members that are not hidden or overridden by members of the derived class ([namespace.udecl]), and type declarations (including injected-class-names) are replaced by the types they designate.
is calculated as follows:
If C contains a declaration of the name f, the declaration set contains every declaration of f declared inC that satisfies the requirements of the language construct in which the lookup occurs.
[ Note
:
As another example, looking up a name in ausing-declaration includes the declaration of a class or enumeration that would ordinarily be hidden by another declaration of that name in the same scope.
— end note
]
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 for the resulting declaration set is empty), is initially empty.
If C has base classes, calculate the lookup set for f in each direct base class subobject , and merge each such lookup set in turn into .
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 name lookup for f in C is the declaration set of .
If it is an invalid set, the program is ill-formed.
[ Example
:
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;
}
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 the name of an overloaded function is unambiguously found, overload resolution ([over.match]) also takes place before access control.
Ambiguities can often be resolved by qualifying a name with its class name.
[ Example
:
struct A { int f(); };
struct B { int f(); };
struct C : A, B { int f() { return A::f() + B::f(); } };
— end example
]
[ Note
:
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
:
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
:
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
:
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 6: Name lookup [fig:class.lookup]
As illustrated in Figure 6, 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
:
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
:
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
]