【问题标题】:Nested generation of comparison operator with three-way operator?比较运算符与三向运算符的嵌套生成?
【发布时间】:2021-06-14 20:56:09
【问题描述】:

考虑以下两个重载operator<=>S

#include <compare>

struct S {};

int operator<=>(S, int) { return 0;  } #1
S   operator<=>(S,   S) { return {}; } #2

如果我将对象Sint 进行比较,#1 将为我生成正确的运算符,因此像S{} &lt;= 00 &lt; S{}0 &lt;=&gt; S{} 这样的表达式将只是fine

但是如果我将一个对象 S 与另一个对象 S 进行比较:

S{} < S{};

然后这将被重写为(S{} &lt;=&gt; S{}) &lt; 0。由于(S{} &lt;=&gt; S{}) 将返回另一个S,我们回到原点问题:Sint 比较。目前,我们没有operator&lt;(S, int),所以#1 会为我生成正确的运算符。

但令人惊讶的是,三个编译器都没有对我这样做。 GCC、Clang 和 MSVC all 拒绝 S{} &lt; S{} 并显示相同的错误消息:

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

这让我很沮丧。由于#1 确实存在。为什么这里没有发生操作符的嵌套生成?标准是怎么说的?是否存在静态约束违规?

【问题讨论】:

  • 您的代码在这两种情况下都不合法。 &lt;=&gt; 必须返回 autostd::strong_orderingstd::weak_orderingstd::partial_orderingboolen.cppreference.com/w/cpp/language/default_comparisons
  • 只需将&lt;=&gt;(S,S) 的返回类型更改为auto,符合标准(据我所知),您仍然会得到相同的行为。
  • @NathanOliver 这仅适用于默认比较(bool 不适用于&lt;=&gt;)。
  • 在链接页面(来自@NathanOliver)的下方进一步查看自定义比较器的返回类型“...有三种可用的返回类型:...”跨度>
  • @RichardCritten 我不确定这是否意味着这些是 only 可能的返回类型。至少,我在标准中找不到限制这一点的相关措辞。

标签: c++ language-lawyer c++20 spaceship-operator


【解决方案1】:

这是格式错误的,尽管错误消息确实令人困惑。

[over.match.oper]/8 的规则是(强调我的):

如果通过重载决议为运算符 @ 选择了重写的 operator&lt;=&gt; 候选者,如果所选候选者是具有相反参数顺序的合成候选者,则 x @ y 被解释为 0 @ (y &lt;=&gt; x),否则 (x &lt;=&gt; y) @ 0 ,使用选定的重写operator&lt;=&gt; 候选。 在结果表达式的上下文中不考虑运算符 @ 的重写候选。

表达式S{} &lt; S{} 将解析为重写后的候选(S{} &lt;=&gt; S{}) &lt; 0。生成的表达式在其查找中不会考虑重写的候选者。因此,当我们执行S{} &lt; 0 时,将寻找只是 operator&lt;,而不是operator&lt;=&gt;。它找不到这样的东西,所以表达式格式不正确。

<source>:8:14: error: no match for 'operator<' (operand types are 'S' and 'int')
    8 | auto x = S{} < S{};
      |          ~~~~^~~~~

从这个意义上说,错误是真的:特别是 operator&lt; 与这些操作数不匹配。虽然如果错误消息有更多的上下文来解释它为什么要寻找它会有所帮助(我在99629提交了一个请求)。

【讨论】:

    猜你喜欢
    • 2021-11-07
    • 2019-03-27
    • 2011-10-29
    • 2018-06-11
    • 1970-01-01
    • 1970-01-01
    • 2015-06-10
    相关资源
    最近更新 更多