Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ spaceship-operator and user-defined types: comparing a subset of attributes only

I have two classes. The first one composing the second one. Both classes have its own synthetized attribute that doesn't collaborate to either ordering or comparision. In addition, I want to usestd::ranges::sort over a container of the second one, so I need to implement a strong-ordering. That's what I have:

struct basic
{
    std::string synthetized; // string representation of the next field.
    unsigned value;
    unsigned property;

    friend bool operator<(basic const& a, basic const& b)
    { return a.value < b.value or (a.value == b.value and a.property < b.property); }
};

struct composed
{
   basic value;
   custom_type meta;

   friend bool operator<(composed const& a, composed const& b)
   { return a.value < b.value; }
};

int main()
{
   std::vector<composed> container;
   // populating container

   // Compilation error here.
   std::ranges::sort(container);
}

How should I appropiately efficiently overload operator<=>? Although what I need is to sort the vector and that's it (I could just go to traditional std::sort), I want to know how to give to both classes full relational capabilities (<, <=, ==, !=, etc) to both classes, but ignoring synthetized and meta, and without doing anything stupid performance-wise.

like image 759
Peregring-lk Avatar asked Sep 19 '25 17:09

Peregring-lk


1 Answers

How should I appropiately efficiently overload operator<=>?

The simplest way to do both would probably be to use std::tie and use the existing function template for operator<=> for tuple types:

template< class... TTypes, class... UTypes >
constexpr /* see link */ operator<=>( const std::tuple<TTypes...>& lhs,
                                      const std::tuple<UTypes...>& rhs );

Example:

#include <tuple>

struct basic {
    std::string synthetized; // excluded from comparisons
    unsigned value;
    unsigned property;

    friend auto operator<=>(basic const& a, basic const& b) {
        return std::tie(a.value, a.property) <=> std::tie(b.value, b.property);
    }
};

struct composed {
    basic value;
    custom_type meta; // excluded from comparisons

    friend auto operator<=>(composed const& a, composed const& b) {
        return a.value <=> b.value;
    }
};

You should also add operator== which will also be used for != so you don't have to overload operator!=.

like image 157
Ted Lyngmo Avatar answered Sep 22 '25 06:09

Ted Lyngmo