Why default three-way operator (spaceship <=>) generates equality operator (==) and user define three-way operator not? [duplicate]
Asked Answered
R

1

10

Consider this code:

#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

Remove comments to get an error.

First I want to ask why default three-way operator behaves differently than user define operator?

And second, is the solution to this problem correct for class C or should it be handled differently?

This is just a simple example and I have more complex situation in mind with tens of fields and unions (If you don't know what I mean, check out some Intel APIs ;) ).

Edit:

This question Equality operator does not get defined for a custom spaceship operator implementation in C++20 focused on why there is no default equality operator for user defined 3-way operator, I would like to know why there is a difference in default and user define behavior?

Edit 2:

I slightly modified class C in the example to picture more of real life problem (when default operators are not valid solution). I also want to clarify that I would like to known the reasons behind those differences (between user define and default operator) to be able to assess if my real life solution is correct (similar to C) as I do value more code maintainability than performance for a part of code that I am working right now.

Racialism answered 28/4, 2020 at 19:25 Comment(1)
I think that this is a duplicate of Equality operator does not get defined for a custom spaceship operator implementation in C++20, unless you’re really asking “Why do I get a defaulted == with a defaulted <=>?”, which doesn’t seem useful.Cherellecheremis
R
10

The principle reason why equality and ordering are separated is performance. If you have a type whose ordering operations are user-defined, then more often than not, you can write a user-defined equality test operation that is more efficient at doing equality tests. And therefore, the language should encourage you to write it by not using operator<=> for direct equality testing.

This only really applies to user-defined ordering/equality operations. Default ordering is member-wise, and default equality operations are also member-wise. And since ordering implies equality, it is reasonable that defaulting ordering also defaults equality.

Yes, they could make people spell it out, but there wasn't really a good reason for that. operator<=> was meant to make it easy to opt-in to default ordering; making you write two declarations for something that's already implied by one of them doesn't make sense.

Rode answered 29/4, 2020 at 1:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.