$7.3.3/14 (C++03)
struct A { int x(); };
struct B : A { };
struct C : A {
using A::x;
int x(int);
};
struct D : B, C {
using C::x;
int x(double);
};
int f(D* d) {
return d->x(); // ambiguous: B::x or C::x
}
The comment in the code in 'f' indicates that one can expect ambiguity between 'B::x' or 'C::x'.
However, on compiling with g++(ideone) or Comeau the errors are slightly different. These errors instead of indicating ambiguity in B::x or C::x indicate the fact that A is an ambiguous base of D
prog.cpp: In function ‘int f(D*)’:
prog.cpp:16: error: ‘A’ is an
ambiguous base of ‘D’
And
"ComeauTest.c", line 21: error: base
class "A" is ambiguous
return d->x(); // ambiguous: B::x or C::x
Going by the name lookup rules in $10.2, I get a feel that the comment in the code snippet is not really correct. The error is indeed first and foremost related to ambiguity of base class 'A' rather than anything else (e.g. ambiguity in overload resolution). Any thoughts?
This is caused by a twist in name-lookup in C++03: Checking for an unambiguous subobject was part of class member name lookup in C++03. Lookup in C++03 will find D::X and C::x and A::x, where A::x matches, but is associated with two distinct subobjects of type A.
In C++0x, the checking for an unambiguous subobject is now part of the respective subclauses, see DR #39: The class where x
is directly a member of is an ambiguous base - so clause 5 will cause a compile error, instead of clause 10.
Note that the comment talks about the subobjects of A
. There is one subobject of A
that goes over path B
, and another subobject of A
that goes over path C
. This is why the comment says "B::x
or C::x
". The presence of multiple subobjects of the same class type can be determined by just trying to convert to its class type, ignoring accessibility issues: If the conversion is ambiguous, the subobject appeared multiple times.
Clang++ gives somewhat a combination of the errors produced by g++ and Comeau
C:\Users\SUPER USER\Desktop>clang++ chubsdad.cpp
chubsdad.cpp(12) : error: ambiguous conversion from derived class 'D' to base class
'A':
struct D -> struct B -> struct A
struct D -> struct C -> struct A
return d->x(); // ambiguous: B::x or C::x
^
1 error generated.