Overload Resolution/Ambiguity in name lookup(which one)
Asked Answered
A

2

4

$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?

Archaic answered 9/11, 2010 at 3:14 Comment(3)
Interestingly, Visual C++ 10.0 compiles the above, choosing the A subobject in B... I could have understood it if it chose the A subobject in C. It seems that g++ and Comeau first resolve the member function as A::x(), and then they discover that d->A::x() is ambiguous. But, interestingly, Visual C++ 10.0 compiles even that!Magnetoelectricity
@Alf P. Steinbach: Yes. It was surprising to me as wellArchaic
Since I don't have a C++03 compiler, I hope this question will be tolerated... What about the use of the virtual keyword as in struct D: virtual B, C or struct D: virtual C, virtual B?Dirichlet
S
2

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.

Suppurate answered 9/11, 2010 at 7:7 Comment(3)
Yes. I remember a previous discussion on this. My point however this time is if the comment in the code sample is really appropriate. For some reason I get a feel that '//ambiguous: B::x or C::x' is in context of overloading, particulary when there are two overloads of 'x' visible in the sampleArchaic
@Archaic the comment does not talk about declarations in B or in C, but about the choice of the subobject of type A. If you had written d->B::x() or d->C::x() you would get no ambiguity, because lookup would start at B and C respectively.Suppurate
In C++0x, the spec is way clearer: There are three clearly distinguished steps: 1) Finding declarations (10.2) and doing overload resolution. This will find A::x. 2) Checking if the object expression is (unambiguously) convertible to the naming class (in a->c naming class and object expression is type of a, but in a->b::c, naming class is b) - 11.2/6. And 3) Checking whether the class where the declaration is directly a member of is an unambiguous base class of the naming class - 5.2.5/5. Your code violates 3).Suppurate
M
0

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.
Mayramays answered 9/11, 2010 at 4:49 Comment(2)
Oh Ok. Thanks. I am not sure though if this answers my question about the appropriateness and the real intent behind the comment in the code snippetArchaic
I think ambiguous: B::x or C::x results from ‘A’ is an ambiguous base of ‘D’. So the comment in the code is correct IMHO.Mayramays

© 2022 - 2024 — McMap. All rights reserved.