In C++17, yes, the only viable candidate was b.operator==(B(a))
.
But in C++20, comparison operators have more functionality. Equality can now consider reversed and rewritten candidates as well. So when consider the expression b == a
we also consider the expression a == b
. As a result, we have two candidates:
bool B::operator==(B const&);
bool A::operator==(A const&); // reversed
The B
member function is an exact match on the left-hand side but requires converting the 2nd argument. The A
member function is an exact match on the right-hand side but requires converting the 1st argument. Neither candidate is better than the other, so the result becomes ambiguous.
As for how to fix it. This is kind of a strange scenario (B
both inherits from A
and is constructible from A
?). if you drop the inheritance, you remove the A
member candidate. If you remove the B(A const&)
constructor, then you get an access violation since the only candidate is the one comparing A
's which requires converting b
to its A
(which kind of suggests that this is questionable).
Alternatively, you could add, to B
, a direct comparison to A
to define what that actually means. Since the issue here is that there are two choices, the compiler doesn't know which one is best, so just provide a better one:
struct B : private A {
B(const A&);
bool operator==(B const&) const;
bool operator==(A const&) const; // <== add this one
};
Now this new one is an exact match in both arguments and is the strictly superior candidate.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…