Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three-way operator <=> return struct with implicit conversion function

Consider the following useless code:

struct S{
  constexpr operator int() const { return 0; }
  constexpr auto operator<=>(S) const { return *this; }
};

static_assert(S{} <= S{});

Clang and MSVC accept this code but GCC rejects it with an error message:

error: no match for 'operator<=' (operand types are 'S' and 'int')

Which compiler is right? How operator<= is synthesized from operator<=>?

like image 271
康桓瑋 Avatar asked Mar 17 '21 04:03

康桓瑋


1 Answers

From [over.match.oper] (3.4.1 and 8):

For the relational ([expr.rel]) operators, the rewritten candidates include all non-rewritten candidates for the expression x <=> y.

and

If a rewritten operator<=> candidate is selected by overload resolution for an operator @, x @ y is interpreted as [...] (x <=> y) @ 0 [...], using the selected rewritten operator<=> candidate. Rewritten candidates for the operator @ are not considered in the context of the resulting expression.

So for the expression S{} <= S{} the selected operator will be S::operator<=>(S) const and the expression will be rewritten as (S{} <=> S{}) <= 0. In the rewritten expression the types of the operands are S and int, for which the built-in operator<=(int, int) will be selected. So ultimately the expression (after converting S to an int) will result in 0 <= 0, which is true.

In conclusion Clang and MSVC are right in this case, and GCC seems to fail in interpreting (S{} <=> S{}) <= 0 as a call to the built-in operator (notice the error message reading operand types are 'S' and 'int'). If you change the condition in the static_assert to be the rewritten expression (S{} <=> S{}) <= 0, then all three compilers accept it.

like image 102
IlCapitano Avatar answered Sep 25 '22 08:09

IlCapitano