This question was inspired by What is wrong with the inheritance hierarchy in my example?
Consider we have a struct B, which can be constructed from const reference to another struct A. Can B be constructed from an object that inherits both A and B?
struct A {};
struct B {
B() {}
B(const A&) {}
};
struct C : A, B {};
B b1(C{}); // 1. ok everywhere
C c;
B b2(c); // 2. ok in MSVC, error in GCC and Clang
The first option with construction from temporary B b1(C{}); is accecpted by all compilers. And the second option with construction from an lvalue B b2(c); is accepted only by MSVC, while both GCC and Clang reject it with the ambiguity error:
error: call of overloaded 'B(C&)' is ambiguous
note: candidate: 'B::B(const A&)'
note: candidate: 'constexpr B::B(const B&)'
Online demo: https://godbolt.org/z/hTM6c5M73
Are GCC and Clang really correct in accepting case 1? And is it correct that they change its mind if one additionly declares default copy constructor in B:
B(const B&) = default;
Online demo: https://godbolt.org/z/9j9xeqY3r
B b2(c);is ambiguous becauseBhas two viable constructors:Both bind the
clvalue directly to their respective parameters, but with rank of a derived-to-base conversion sequence (rather than the identity sequence) per [over.ics.ref]/1. The conversion sequences are indistinguishable in terms of best overload, because neither isAderived fromBnor isBderived fromA. None of the rules in [over.ics.rank]/3 and [over.ics.rank]/4 distinguish them.B b1(C{});is unambiguous, because there is another viable overloadAgain, the reference binding is a considered a derived-to-base conversion sequence, i.e. the conversion rank is the same as before.
But because the argument is bound directly to a rvalue reference, it is considered better than the other two overloads which only bind directly to lvalue references per [over.ics.rank]/3.2.3.
Adding
B(const B&) = default;modifies the overload set by removing theB(B&&);move constructor, because it won't be implicitly-declared if there is a user-declared copy constructor per [class.copy.ctor]/8.1.Then
B b1(C{});is ambiguous between the other two remaining overloads as before.