【问题标题】:Why default three-way operator (spaceship <=>) generates equality operator (==) and user define three-way operator not?为什么默认三通运算符(spaceship <=>)生成相等运算符(==)而用户定义三通运算符不?
【发布时间】:2020-08-12 17:58:25
【问题描述】:

考虑这段代码:

#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

删除 cmets 会出错。

首先我想问一下为什么默认的三通操作符与用户定义操作符的行为不同?

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

这只是一个简单的例子,我想到了更复杂的情况,有数十个字段和联合(如果你不明白我的意思,请查看一些英特尔 API ;))。

编辑:

这个问题Equality operator does not get defined for a custom spaceship operator implementation in C++20的重点是为什么用户定义的3路运算符没有默认的相等运算符,我想知道为什么默认和用户定义的行为有区别?

编辑 2:

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

【问题讨论】:

标签: c++ operator-overloading c++20 spaceship-operator


【解决方案1】:

principle reason 将相等和排序分开的原因在于性能。如果您有一个排序操作是用户定义的类型,那么通常情况下,您可以编写一个用户定义的相等测试操作,该操作在执行相等测试时更有效。因此,该语言应该鼓励您编写它,不要使用operator&lt;=&gt; 进行直接相等测试。

这只真正适用于用户定义的排序/相等操作。默认排序是按成员的,默认的相等操作也是按成员的。而且由于排序意味着相等,因此默认排序也默认相等是合理的。

是的,他们可以让人们把它拼出来,但是there wasn't really a good reason for thatoperator&lt;=&gt; 旨在让您轻松选择默认排序;让你为其中一个已经暗示的东西写两个声明是没有意义的。

【讨论】:

  • 唯一改变的是C不再是成员的直接比较。这与您问题的主要主旨没有真正的关系,这就是为什么operator== 不会自动调用operator&lt;=&gt;。如果您想以这种方式定义您的==,您可以,但系统不会为您这样做。
猜你喜欢
  • 1970-01-01
  • 2018-09-26
  • 1970-01-01
  • 2021-06-14
  • 2013-06-28
  • 1970-01-01
  • 1970-01-01
  • 2021-05-11
  • 2018-09-10
相关资源
最近更新 更多