哪些是!=运算符的重写候选者
标准中的相关规则说:
over.match.oper#3.4.3
重写的候选集确定如下:
- 对于关系 ([expr.rel]) 运算符,重写的候选项包括表达式 x <=> y 的所有未重写的候选项。
- 对于关系([expr.rel])和三路比较([expr.spaceship])算子,重写的候选者还包括一个合成的候选者,两个参数的顺序颠倒了,对于每个未重写的候选者表达式 y <=> x。
- 对于 != 运算符 ([expr.eq]),重写的候选项包括表达式 x == y 的所有未重写的候选项。
- 对于等式运算符,对于表达式 y == x 的每个未重写候选,重写候选还包括一个合成候选,两个参数的顺序颠倒。
- 对于所有其他算子,重写的候选集为空。
考虑以下代码:
#include <iostream>
struct Data{
bool operator ==(int c){
return true;
}
};
int main(){
Data d;
bool r = 0 != d; // should be ill-formed
}
我不知道为什么代码可以被编译器编译。IMO,表达式的重写候选0!=d
应包括表达式 x == y 的所有未重写候选。我对非重写候选的措辞的理解是,考虑除表达式 x==y 的重写候选之外的任何候选,用于操作 x != y。毕竟,子弹 4 用于形成重写的候选集。因此,第四项不应继续适用于x==y
已为原始表达式重写的x!=y
。在我的例子中,重写的候选集0!=d
只包含 for 0==d
,它不应该考虑任何重写的候选d==0
;
本页中有关非重写措辞的相关规则与我的解释类似。(不包括改写的候选人)
对于 != 运算符 ([expr.eq]),重写的候选项包括表达式 x == y 的所有成员、非成员和内置候选项。
不过,继续看下一段,那就是:
如果通过重载决议为 operator@ 选择了重写的 operator== 候选者,则其返回类型应为 cv bool,并且 x@y 被解释为:
- 如果@ 是 != 并且所选候选是一个合成候选,参数顺序相反,!(y == x),
既然重写后的候选!=
不能继续重写,那怎么会有参数倒序的合成候选呢?我不知道为什么。如何解释重写的候选规则!=
,尤其是非重写候选和最后一条规则的措辞?
回答
我怀疑这是由[over.match.oper]/3.4.4授予的:
对于等式运算符,对于表达式 y == x 的每个未重写候选,重写候选还包括一个合成候选,两个参数的顺序颠倒。
平等运营商都 operator==
和operator!=
。还要注意“综合”不是“重写”的同义词:四组候选是成员候选、非成员候选、内置候选和重写候选。合成候选仅属于这些集合中的一个(在这种情况下是重写候选的集合)。
因此,我的理解是重写的候选对象x != y
包括
- 的所有未重写候选者
x == y
,以及 - 的非重写候选的合成候选
y == x
。
所以合成的候选者y == x
也是重写的候选者。然后[over.match.oper]/9.1开始:
如果
@
是!=
并且所选候选者是参数顺序相反的合成候选者,!(y == x)
也就是说,如果选择的重写候选是上面合成的候选y == x
,那么结果将是!(y == x)
。