Почему трехсторонний оператор по умолчанию (космический корабль <=>) генерирует оператор равенства (==), а трехсторонний оператор пользователь не определяет? - PullRequest
0 голосов
/ 28 апреля 2020

Рассмотрите этот код:

#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-интерфейсы Intel;)).

Редактировать:

Этот вопрос Оператор равенства не определен для реализации пользовательского оператора космического корабля в C ++ 20 , сфокусированный на том, почему не существует оператора равенства по умолчанию для определяемого пользователем 3-стороннего оператора. Я хотел бы знать, почему существует разница по умолчанию и поведение, определяемое пользователем?

Редактировать 2:

Я немного изменил класс C в примере, чтобы представить больше реальной проблемы (когда операторы по умолчанию не являются допустимым решением ). Я также хочу уточнить, что я хотел бы знать причины этих различий (между определением пользователя и оператором по умолчанию), чтобы иметь возможность оценить, является ли мое реальное решение правильным (аналогично C), поскольку я ценю больше поддерживаемости кода чем производительность для части кода, над которым я сейчас работаю.

1 Ответ

2 голосов
/ 29 апреля 2020

Принципиальная причина , по которой равенство и порядок разделены, - это производительность. Если у вас есть тип, чьи операции упорядочения определяются пользователем, то чаще всего вы можете написать пользовательскую тестовую операцию на равенство, которая более эффективна при выполнении тестов на равенство. И поэтому язык должен побуждать вас писать его, не используя operator<=> для прямого тестирования на равенство.

Это действительно относится только к определяемым пользователем операциям упорядочения / равенства. Порядок по умолчанию является членским, а операции равенства по умолчанию также являются членскими. А так как упорядочение подразумевает равенство, разумно, что по умолчанию упорядочение также подразумевает равенство.

Да, они могут заставить людей разобрать его, но на самом деле не было веской причины для этого . operator<=> предназначался для упрощения выбора порядка по умолчанию; заставлять вас писать два объявления для того, что уже подразумевается одним из них, не имеет смысла.

...