c++ - 比较运算符与三向运算符的嵌套生成?
问题描述
考虑以下两个重载operator<=>
:S
#include <compare>
struct S {};
int operator<=>(S, int) { return 0; } #1
S operator<=>(S, S) { return {}; } #2
如果我将一个对象S
与 进行比较int
,则会为我生成正确的运算符,所以像, or#1
这样的表达式就可以了。S{} <= 0
0 < S{}
0 <=> S{}
但是,如果我将一个对象S
与其他对象进行比较S
:
S{} < S{};
那么这将被重写为(S{} <=> S{}) < 0
. 既然(S{} <=> S{})
会返回一个 other S
,我们回到原点问题:S
与 a 比较int
。目前,我们没有operator<(S, int)
,因此#1
将为我生成正确的运算符。
但令人惊讶的是,三个编译器都没有对我这样做。GCC、Clang 和 MSVC都拒绝S{} < S{}
并显示相同的错误消息:
no match for 'operator<' (operand types are 'S' and 'int')
这让我很沮丧。由于#1
实际存在。为什么这里没有发生操作符的嵌套生成?标准是怎么说的?是否存在静态约束违规?
解决方案
这是格式错误的,尽管错误消息确实令人困惑。
来自[over.match.oper]/8的规则是(强调我的):
如果
operator<=>
通过重载决议为运算符选择了重写的候选者@
,则将其x @ y
解释为0 @ (y <=> x)
好像所选候选者是具有相反参数顺序的合成候选者,或者(x <=> y) @ 0
以其他方式使用所选的重写operator<=>
候选者。在结果表达式的上下文中不考虑运算符的重写候选。@
表达式S{} < S{}
将解析为重写的候选者(S{} <=> S{}) < 0
。生成的表达式在其查找中不会考虑重写的候选者。所以当我们这样做的时候S{} < 0
,就是要寻找只是一个operator<
,而不是也operator<=>
。它找不到这样的东西,所以表达式是不正确的。
<source>:8:14: error: no match for 'operator<' (operand types are 'S' and 'int')
8 | auto x = S{} < S{};
| ~~~~^~~~~
从这个意义上说,这个错误是真的:没有匹配项,特别 operator<
是那些操作数。虽然如果错误消息有更多的上下文来解释它为什么要寻找它(并且我在99629中提交了一个请求),这会有所帮助。
推荐阅读
- kubernetes - 外部服务的 Kubernetes 入口规则
- reactjs - 使用反应表中的选择下拉列表过滤数据
- git - 在 CI 中的克隆操作期间如何对 github 子模块进行身份验证?
- c# - 反序列化 XML 文件属性
- python - 有人可以帮我在 Python 中使用 pip 吗?
- webrtc - 连接问题 webRTC 应用程序。只能在本地工作,不能在移动设备上工作
- c# - 并行运行多个任务会导致 System.AggregateException
- javascript - 使用 Telegraf/Node.js 等待消息响应
- java - 如何配置 ResourceHttpRequestHandler 支持的方法?
- json - Power Query Editor (Excel) - 错误处理 API 提要中的无数据