Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to satisfy totally_ordered for a custom type without spaceship comparison operator (ranges::is_sorted, ranges::sort)

Consider the following code:

#include <vector>
#include <algorithm>
#include <ranges>
#include <cassert>

// The type is defined in legacy code and we can not change it
struct A
{
   int a;
};

bool operator <(const A &a1, const A &a2)
{
   return a1.a < a2.a;
}

int main()
{
   assert(A {} < A{}); // OK
   std::vector<A> c;
   assert(std::ranges::is_sorted(c)); // compilation error
}

The code can be fixed by adding the "spaceship" comparison operator to A:

auto operator<=>(const A &) const = default;

However, defining it outside of a class works with the first assert, but not the second:

auto operator <=>(const A &a1, const A &a2) { return a1.a <=> a2.a; }

Is it possible to satisfy the requirements of ranges::less without modifying A?

like image 419
Alexander Bessonov Avatar asked Oct 16 '25 00:10

Alexander Bessonov


1 Answers

You need to provide an == as well as <=>. std::ranges::less requires std::totally_ordered not just std::strict_weak_order, so == is also needed. Unless defaulted, <=> doesn't synthesize ==.

#include <vector>
#include <algorithm>
#include <ranges>
#include <cassert>

// The type is defined in legacy code and we can not change it
struct A
{
   int a;
};

auto operator <=>(const A &a1, const A &a2) { return a1.a <=> a2.a; }
auto operator ==(const A &a1, const A &a2) { return a1.a == a2.a; }

int main()
{
   assert(A {} < A{}); // Comparison exists
   std::vector<A> c;
   assert(std::ranges::is_sorted(c)); // Comparison exists
}
like image 106
Caleth Avatar answered Oct 18 '25 16:10

Caleth



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!