简体   繁体   English

三路运算符 <=> 隐式转换返回结构 function

[英]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: Clang 和 MSVC 接受此代码,但 GCC拒绝它并显示错误消息:

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

Which compiler is right?哪个编译器是对的? How operator<= is synthesized from operator<=> ? operator<=如何从operator<=>合成?

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

For the relational ([expr.rel]) operators, the rewritten candidates include all non-rewritten candidates for the expression x <=> y.对于关系 ([expr.rel]) 运算符,重写的候选包括表达式 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.如果通过重载决策为operator @选择了重写的operator<=>候选者,则x @ y被解释为 [...] (x <=> y) @ 0 [...],使用所选的重写operator<=>候选人。 Rewritten candidates for the operator @ are not considered in the context of the resulting expression.在结果表达式的上下文中不考虑operator @的重写候选。

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 .因此,对于表达式S{} <= S{} ,选定的运算符将是S::operator<=>(S) const并且表达式将被重写为(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.在重写的表达式中,操作数的类型是Sint ,将选择内置的operator<=(int, int) So ultimately the expression (after converting S to an int ) will result in 0 <= 0 , which is true .所以最终表达式(在将S转换为int之后)将导致0 <= 0 ,这是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' ).总之 Clang 和 MSVC 在这种情况下是正确的,并且 GCC 似乎无法将(S{} <=> S{}) <= 0解释为对内置运算符的调用(请注意读取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 .如果您将static_assert中的条件更改为重写后的表达式(S{} <=> S{}) <= 0 ,则所有三个编译器都接受它

C++20 support in GCC is still experimental , so while it does support the three-way operator , your static_assert is failing because the other compilers are auto inferring the <= operator from the <=> operator, while GCC seems to be more pedantic in its interpretation of the standard, and since you do not have the <= operator directly, the compiler is then emitting a compile time error because it can't find the <= operator. GCC 中的 C++20 支持仍处于实验阶段,因此虽然它支持三向运算符,但您的static_assert失败,因为其他编译器自动从<=>运算符推断<=运算符,而 GCC 似乎更多对标准的解释很迂腐,并且由于您没有直接使用<=运算符,因此编译器会发出编译时错误,因为它找不到<=运算符。

If you add the <= operator, the code works, example:如果添加<=运算符,则代码有效,例如:

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

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

Additionally, if you change your assert to be the three way operator, the test fails on all compilers, example:此外,如果您将断言更改为三向运算符,则测试在所有编译器上都会失败,例如:

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

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

Furthermore, since the three-way operator is expected to essentially return a negative, zero, or positive value (really returning an ordering), returning *this is likely converting the value to something that Clang and MSVC interpret as a true value for the assert, while GCC could be converting it to a false value, and thus the assert fails.此外,由于预计三路运算符基本上返回负值、零或正值(实际上返回一个排序),返回*this可能会将值转换为 Clang 和 MSVC 解释为断言的true值的值,而 GCC 可能会将其转换为false值,因此断言失败。

If you change the return type to any negative value (even -0 ) or a zero value, the assert passes on all compilers, additionally if you change the value to any positive value above 0 the assert fails on all compilers.如果您将返回类型更改为任何负值(甚至-0 )或零值,则断言将传递给所有编译器,此外,如果您将值更改为任何高于 0 的正值,则断言在所有编译器上都会失败。

You could change the three-way operator to cast *this to an int which would call operator int and return 0, which would then cause the assert to pass, example:您可以将三向运算符更改为将*this强制转换为int ,该 int 将调用operator int并返回 0,这将导致断言通过,例如:

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

So to answer directly:所以直接回答:

Which compiler is right?哪个编译器是对的?

In my experience with GCC, it tends to interpret the language very pedantically and err on the side of caution when it comes to a language specification that might be ambiguous in the face of an odd code snippet (like yours).根据我对 GCC 的经验,当涉及到面对奇怪的代码片段(如您的代码片段)可能模棱两可的语言规范时,它往往会非常迂腐地解释语言,并且会谨慎行事。

To that end, the other compilers might be too loose in their interpretation of the language or GCC might be too strict in this particular case.为此,其他编译器对语言的解释可能过于松散,或者 GCC 在这种特殊情况下可能过于严格。

Either way, even though this code is "useless," anyone who is running into something like this who is targeting all 3 compilers should probably try to be as pedantic as possible with this type of code, though that might necessarily defeat the purpose of the code in this case, unfortunately.无论哪种方式,即使这段代码是“无用的”,任何遇到这样的事情并针对所有 3 个编译器的人都应该尽可能地尝试使用这种类型的代码,尽管这可能必然会违背不幸的是,这种情况下的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 三向比较运算符总是有效吗? - Is the three-way comparison operator always efficient? 为什么默认三通运算符(spaceship &lt;=&gt;)生成相等运算符(==)而用户定义三通运算符不? - Why default three-way operator (spaceship <=>) generates equality operator (==) and user define three-way operator not? 比较运算符与三向运算符的嵌套生成? - Nested generation of comparison operator with three-way operator? 顺序推导不一致的三向比较算子 - Three-way comparison operator with inconsistent ordering deduction C++ 中的 &lt;=&gt;(“宇宙飞船”,三路比较)运算符是什么? - What is the <=> ("spaceship", three-way comparison) operator in C++? 三向比较运算符与减法有何不同? - How is the three-way comparison operator different from subtraction? 三路比较和constexpr函数模板:哪个编译器是对的? - Three-way comparison and constexpr function template: which compiler is right? 将三路比较运算符的结果与 nullptr 进行比较有什么作用? - What does comparing the result of the three-way comparison operator with nullptr do? 三向比较运算符成员与非成员实现 - Three-way comparison operator member vs non-member implementation 如何使用三路比较(spaceship op)实现不同类型之间的operator==? - How to use three-way comparison (spaceship op) to implement operator== between different types?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM