为什么默认的三向运算符(宇宙飞船<=>)生成相等运算符(==)而用户定义三向运算符不?



考虑以下代码:

#include <iostream>
#include <compare>
class A {
public:
int i = {};
std::strong_ordering operator<=> (A const& r) const
{
return i <=> r.i;
}
};
void TestA()
{
A a;
A b;
std::cout<< (a<b);    
std::cout<< (a>b);
std::cout<< (a<=b);
std::cout<< (a>=b);
//std::cout<< (a==b); //ERROR
std::cout << 'E';
//std::cout<< (a!=b); //ERROR
std::cout << 'E';
std::cout<< std::is_eq(a<=>b);
std::cout<< std::is_neq(a<=>b) << std::endl;
}
class B {
public:
int i = {};
std::strong_ordering operator<=> (B const& r) const = default;
};

void TestB()
{
B a;
B b;
std::cout<< (a<b);    
std::cout<< (a>b);
std::cout<< (a<=b);
std::cout<< (a>=b);
std::cout<< (a==b);
std::cout<< (a!=b);
std::cout<< std::is_eq(a<=>b);
std::cout<< std::is_neq(a<=>b) << std::endl;
}
class C {
public:
bool b = {};
int v1 = {};
int v2 = {};
std::strong_ordering operator<=> (C const& r) const
{
return (b?v1:v2) <=> (r.b?r.v1:r.v2);
}
bool operator== (C const& r) const
{
return std::is_eq(*this<=>r);
}
};
void TestC()
{
C a;
C b;
std::cout<< (a<b);    
std::cout<< (a>b);
std::cout<< (a<=b);
std::cout<< (a>=b);
std::cout<< (a==b);
std::cout<< (a!=b);
std::cout<< std::is_eq(a<=>b);
std::cout<< std::is_neq(a<=>b) << std::endl;
}

int main()
{    
TestA();
TestB();
TestC();
return 0;
}

https://wandbox.org/permlink/SLmLZOc18RaJV7Mu

删除注释以获得错误。

首先,我想问一下,为什么默认的三元运算符的行为与用户定义运算符不同?

其次,这个问题的解决方案对C类来说是正确的,还是应该以不同的方式处理?

这只是一个简单的例子,我想到了几十个字段和并集的更复杂的情况(如果你不知道我的意思,请查看一些英特尔API;(。

编辑:

这个问题Equality操作符没有为C++20中的自定义宇宙飞船操作符实现定义。重点是为什么用户定义的三向操作符没有默认的Equality运算符,我想知道为什么默认和用户定义的行为有区别?

编辑2:

我在示例中稍微修改了C类,以描绘更多现实生活中的问题(当默认运算符不是有效的解决方案时(。我还想澄清一下,我想知道这些差异背后的原因(用户定义和默认运算符之间(,以便能够评估我的现实生活解决方案是否正确(类似于C(,因为我确实更看重代码的可维护性,而不是我现在正在工作的代码部分的性能。

等式和排序分离的主要原因是性能。如果您有一个排序操作是用户定义的类型,那么通常情况下,您可以编写一个用户定义的相等测试操作,该操作在执行相等测试时更有效。因此,该语言应该鼓励您通过不使用operator<=>进行直接相等测试来编写它。

这只适用于用户定义的排序/相等操作。默认排序是按成员排序的,默认相等操作也是按成员排序。由于排序意味着相等,所以默认排序也默认相等是合理的。

是的,他们可以让人们把它拼出来,但这并不是一个很好的理由。operator<=>旨在使选择默认排序变得容易;让你为其中一个已经暗示的东西写两个声明是没有意义的。

相关内容

最新更新