std::ranges::make_heap
uses std::ranges::less
, which has a constraint:
Unlike std::less
, std::ranges::less
requires all six comparison operators <
, <=
, >
, >=
, ==
and !=
to be valid (via the totally_ordered_with
constraint).
Your type S
does not have an equality operator; the spaceship operator only provides the other comparison operators.*
To fix this, provide an operator==
for your type:
constexpr auto operator==(const S& s) const {
return i == s.i;
}
Godbolt Link: https://godbolt.org/z/cGfrxs
* operator<=>
does not imply operator==
for performance reasons, as operator==
can short circuit over collections whereas operator<=>
cannot. However, from https://en.cppreference.com/w/cpp/language/default_comparisons , we see that a defaulted operator<=>
will also implicitly default an operator==
.
How did I figure this out? The error message for your code includes the following (trimmed and word wrapped by me):
note: the expression 'is_invocable_v<_Fn, _Args ...>
[with _Fn = std::ranges::less&; _Args = {value_type&, value_type&}]'
evaluated to 'false'
338 | concept invocable = is_invocable_v<_Fn, _Args...>;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This means that std::ranges::make_heap
finds that it can't call std::ranges::less
for our type. Repeating this error message investigation for std::ranges::less
on the value_type
of the vector yields:
note: no operand of the disjunction is satisfied
123 | requires totally_ordered_with<_Tp, _Up>
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124 | || __detail::__less_builtin_ptr_cmp<_Tp, _Up>
At this point, the compiler is trying hard to tell us that we aren't satisfying totally_ordered_with
, which means that it's time to hit the documentation for the concept and for std::ranges::less
.