简体   繁体   中英

what are the constraints for std::ranges::make_heap?

The following code works well with gcc:

struct S {
  int i, j;
  auto operator<(const S& s) const {
    return i < s.i;
  };
};
std::vector<S> v;
std::make_heap(v.begin(), v.end());

But when I switch to C++20's range algorithm:

std::ranges::make_heap(v);

I got this compiler error:

source>:14:27: error: no match for call to '(const std::ranges::__make_heap_fn) (std::vector<S>&)'
14 |   std::ranges::make_heap(v);
   |    
                   ^

It seems struct S doesn't satisfy the requirements of the ranges::make_heap , but I don't know what exactly it is, can someone help?

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM