当前位置: 首页 > 知识库问答 >
问题:

用三向算子嵌套生成比较算子?

贺善
2023-03-14

考虑以下两个用于s的重载运算符<=>:

#include <compare>

struct S {};

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

如果我将对象Sint进行比较,#1将为我生成正确的运算符,所以像S{}<=00 0<=>S{}这样的表达式就可以了。

但如果我将一个对象s与其他对象s:

S{} < S{};

则将重写为(S{}<=>S{})<0。由于(S{}<=>S{})将返回另一个S,所以我们回到原始问题:Sint进行比较。此时,我们没有运算符<(S,int),因此#1将为我生成正确的运算符。

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

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

这让我很沮丧。因为#1实际存在。为什么不在这里产生运算符的嵌套生成?标准是怎么说的?是否存在静态约束冲突?


共有1个答案

白昊东
2023-03-14

这是错误的,尽管错误消息是相当混乱的。

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

如果通过重载解析为运算符@选择了重写的运算符<=>候选,则如果选定的候选是参数顺序相反的合成候选,则x@y被解释为0@(y<=>x);否则,则使用选定的重写的运算符<=>候选。在结果表达式的上下文中不考虑操作符@的重写候选项。

表达式S{} 将解析为重写的候选 (S{}<=>S{})<0。结果表达式将不会在其查找中考虑重写的候选项。因此,当我们执行 s{}<0时,只需要查找一个 运算符<,而不是 运算符<=>。它找不到这样的东西,所以表达方式是畸形的。

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

在这个意义上,错误是真的:没有匹配,特别是operator<与这些操作数。尽管如果错误消息中有更多的上下文来解释为什么要查找这些信息,这将会有所帮助。

 类似资料:
  • 我有以下结构: 我正在寻找一种算法,如何从创建一个类似父子嵌套的结构。 逻辑是这样的: 假设:列表中的第一项总是以深度=0开头 如果深度大于最后一个,它必须是最后一个的孩子 我没法让它工作。它应该是递归的,具有无限嵌套/深度级别。 谢谢你们的帮助!

  • 问题内容: 我一直在尝试使用嵌套形式,如下所示: 但似乎我缺少了一些东西。谁能协助我该怎么做? 问题答案: 将其括在括号中: 甚至更好的是,使用适当的/ 语句(出于可维护性): 但是,正如其他人指出的那样:使用起来更简单:

  • C++20中有一个新的比较运算符。然而,我认为在大多数情况下,一个简单的减法效果很好: 它们的效果是一样的。我真的不明白这有什么区别。

  • Herb Sutter在他关于“宇宙飞船”操作员的建议(第12页底部第2.2.2节)中说: 基于及其返回类型:该模型具有主要优点,与以前针对C++的建议和其他语言的功能相比,该建议具有一些独特之处: [...] (6)效率,包括最终实现对比较的零开销抽象:绝大多数的比较总是单程通过的。唯一的例外情况是在同时支持偏序和相等的类型的情况下生成和。对于,单次传递对于实现零开销原则以避免重复相等比较至关重

  • < > <= >= == ~= 分别表示 小于,大于,不大于,不小于,相等,不相等 所有这些操作符总是返回 true 或 false。 对于 Table,Function 和 Userdata 类型的数据,只有 == 和 ~=可以用。相等表示两个变量引用的是同一个数据。比如: a={1,2} b=a print(a==b, a~=b) -- true, false a={1,2} b={1,2}

  • 当我试图学习C++运算符的时候,我无意中在cppreference.com上发现了一个奇怪的比较运算符,*在如下表中: “好吧,如果这些是C++中常见的运算符,我最好学会它们”,我想。但我想要弄清楚这个谜团的一切努力都没有成功。即使在这里,在堆栈溢出,我没有运气在我的搜索。 如果有的话,这个运算符到底是做什么的? *同时CPPreference.com更新了该页,现在包含有关运算符的信息。