Why doesn't a using-declaration work to solve the diamond problem?
Solution 1:
Someone else can find the standard quote but I'm going to explain conceptually.
It doesn't work because a using-declaration only affects name lookup.
Your using-declaration causes name lookup to succeed where it would otherwise fail, that is, it tells the compiler where to find the function f
. But it does not tell it which A
subobject f
acts on, that is, which one will be passed as the implicit this
parameter when f
is called.
There is only a single function A::f
even though there are two A
subobjects of C
, and it takes an implicit this
argument of type A*
. In order to call it on a C
object, C*
must be implicitly converted to A*
. This is always ambiguous, and is not affected by any using-declarations.
(This makes more sense if you put data members inside A
. Then C
would have two of each such data member. When f
is called, if it accesses data members, does it access the ones in the A
subobject inherited from B1
, or the ones in the A
subobject inherited from B2
?)
Solution 2:
There's a note in [namespace.udecl]/p17 that addresses this situation directly:
[ Note: Because a using-declaration designates a base class member (and not a member subobject or a member function of a base class subobject), a using-declaration cannot be used to resolve inherited member ambiguities. For example,
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 }
—end note ]