Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguity in case of multiple inheritance and spaceship operator in C++20

In the following simplified program, struct C inherits from two structs A and B. The former defines both spaceship operator <=> and less operator, the latter – only spaceship operator. Then less operation is performed with objects of class C:

#include <compare>

struct A { 
    auto operator <=>(const A&) const = default;
    bool operator <(const A&) const = default;
};
struct B { 
    auto operator <=>(const B&) const = default; 
};
struct C : A, B {};
int main() { 
    C c;
    c.operator<(c); //ok everywhere
    return c < c;   //error in GCC
}

The surprising moment here is that the explicit call c.operator<(c) succeeds in all compliers, but the similar call c<c is permitted by Clang but rejected in GCC:

error: request for member 'operator<=>' is ambiguous
<source>:8:10: note: candidates are: 'auto B::operator<=>(const B&) const'
<source>:4:10: note:                 'constexpr auto A::operator<=>(const A&) const'

Demo: https://gcc.godbolt.org/z/xn7W9PaPc

There is a possibly related question: GCC can't differentiate between operator++() and operator++(int) . But in that question the explicit operator (++) call is rejected by all compilers, unlike this question where explicit operator call is accepted by all.

I thought that only one operator < is present in C, which was derived from A, and starship operator shall not be considered at all. Is it so and what compiler is right here?

like image 588
Fedor Avatar asked Sep 19 '21 05:09

Fedor


People also ask

What is ambiguity problem in case of multiple inheritance?

Ambiguity in Multiple Inheritance. The ambiguity that arises when using multiple inheritance refers to a derived class having more than one parent class that defines property[s] and/or method[s] with the same name.

What is ambiguity in multiple inheritance how it can be resolved?

An ambiguity can arise when several paths exist to a class from the same base class. This means that a child class could have duplicate sets of members inherited from a single base class. This can be solved by using a virtual base class.

What is multiple inheritance What is the ambiguity in multiple inheritance give suitable example to demonstrate multiple inheritance?

Inheritance Ambiguity in C++ In multiple inheritances, when one class is derived from two or more base classes then there may be a possibility that the base classes have functions with the same name, and the derived class may not have functions with that name as those of its base classes.

Which type of inheritance leads to ambiguity problem?

Multiple inheritance has been a controversial issue for many years, with opponents pointing to its increased complexity and ambiguity in situations such as the "diamond problem", where it may be ambiguous as to which parent class a particular feature is inherited from if more than one parent class implements said ...

What is the ambiguity problem in multiple inheritance?

The most obvious error with Multiple Inheritance is Ambiguity errors, this occurs during function overriding. Do you want to learn how I can solve the Ambiguity problem in Multiple Inheritance? This question is also the same as how I can solve the Ambiguity problem in Class methods? To explain this, first, let’s give an example.

Can spaceship operator be rewritten in c++20?

Let’s explore the answer to this question. In C++20, the compiler is introduced to a new concept referred to “rewritten” expressions. The spaceship operator, along with operator==, are among the first two candidates subject to rewritten expressions.

What is 3-way comparison operator (space ship operator) in c++ 20?

3-way comparison operator (Space Ship Operator) in C++ 20. Difficulty Level : Expert. Last Updated : 24 Nov, 2020. The three-way comparison operator “<=>” is called a spaceship operator. The spaceship operator determines for two objects A and B whether A < B, A = B, or A > B. The spaceship operator or the compiler can auto-generate it for us.

What is ambiguity error in C++?

If we try to call the function using the object of the derived class, the compiler will show us an Ambiguity error, because there is a conflict with two same names and the compiler doesn’t know which function to call. For example, If we run this code above in C++, we will face with Ambiguity Error as in here,


1 Answers

gcc is correct here.

When you do:

c.operator<(c);

You are performing name lookup on something literally named operator<. There is only one such function (the one in A) so this succeeds.

But when you do c < c, you're not doing lookup for operator<. You're doing two things:

  1. a specific lookup for c < c which finds operator< candidates (member, non-member, or builtin)
  2. finding all rewritten candidates for c <=> c

Now, the first lookup succeeds and finds the same A::operator< as before. But the second lookup fails - because c <=> c is ambiguous (between the candidates in A and B). And the rule, from [class.member.lookup]/6 is:

The result of the search is the declaration set of S(N,T). If it is an invalid set, the program is ill-formed.

We have an invalid set as the result of the search, so the program is ill-formed. It's not that we find nothing, it's that the whole lookup fails. Just because in this context we're looking up a rewritten candidate rather than a primary candidate doesn't matter, it's still a failed lookup.


And it's actually good that it fails because if we fix this ambiguous merge set issue in the usual way:

  struct C : A, B {
+     using A::operator<=>;
+     using B::operator<=>;
  };

Then our lookup would be ambiguous! Because now our lookup for the rewritten candidates finds two operator<=>s, so we end up with three candidates:

  1. operator<(A const&, A const&)
  2. operator<=>(A const&, A const&)
  3. operator<=>(B const&, B const&)

1 is better than 2 (because a primary candidate is better than a rewritten candidate), but 1 vs 3 is ambiguous (neither is better than the other).

So the fact that the original fails, and this one also fails, is good: it's up to you as the class author to come up with the right thing to do - since it's not obvious what that is.

like image 97
Barry Avatar answered Oct 21 '22 01:10

Barry