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 ]