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.
CodePudding user response:
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!=
.
CodePudding user response:
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.
Define comparison member functions for your type
#include <string>
struct basic
{
std::string synthetized; // string representation of the next field.
unsigned value;
unsigned property;
constexpr auto operator<=>(const basic& other) const noexcept {
if (auto c = value <=> other.value; c != 0)
return c;
return property <=> other.property;
}
constexpr bool operator==(const basic& other) const noexcept {
return value == other.value && property == other.property;
}
};
struct composed
{
basic value;
custom_type meta;
constexpr auto operator<=>(const composed& other) const noexcept {
return value <=> other.value;
}
constexpr bool operator==(const composed& other) const noexcept {
return value == other.value;
}
};
Note that in your example operator<=>
does not synthesize operator==
because it is not the default, so you still need to define operator==
for your type to satisfy total_ordered_with
.