c++ - std::ranges::make_heap的约束是什么?

标签 c++ c++20 std-ranges

以下代码可与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());
但是当我切换到C++ 20的范围算法时:
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);
   |    
                   ^
看来struct S不能满足ranges::make_heap的要求,但是我不知道它到底是什么,有人可以帮忙吗?

最佳答案

std::ranges::make_heap使用 std::ranges::less ,它具有一个约束:

Unlike std::less, std::ranges::less requires all six comparison operators <, <=, >, >=, == and != to be valid (via the totally_ordered_with constraint).


您的类型S没有相等运算符;飞船运算符仅提供其他比较运算符。*
要解决此问题,请为您的类型提供一个operator==:
constexpr auto operator==(const S& s) const {
  return i == s.i;
}
Godbolt链接:https://godbolt.org/z/cGfrxs
*出于性能原因,operator<=>并不暗示operator==,因为operator==可以使集合短路,而operator<=>则不能。但是,从https://en.cppreference.com/w/cpp/language/default_comparisons中,我们看到默认的operator<=>也将隐式默认为operator==

我是怎么知道的?您的代码的错误消息包括以下内容(由我整理和包装):
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...>;
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

这意味着std::ranges::make_heap发现它无法为我们的类型调用std::ranges::less。对 vector 的std::ranges::less上的value_type重复此错误消息调查,将得出:
note: no operand of the disjunction is satisfied
  123 |       requires totally_ordered_with<_Tp, _Up>
      |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  124 |         || __detail::__less_builtin_ptr_cmp<_Tp, _Up>

在这一点上,编译器正在努力告诉我们,我们不满意totally_ordered_with,这意味着该是时候阅读有关概念和std::ranges::less的文档了。

关于c++ - std::ranges::make_heap的约束是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64708867/

相关文章:

c++ - 两次调用timer_settime会产生错误

c# - VC++ 中 "object of C# "的等价物是什么?

c++ - std::is_trivially_equality_comparable_v<T>

c++ - 在 C++20 中将多个范围适配器连接成一个范围

c++ - 有没有一种干净的方法来使用范围分割逗号和空格分隔的单词?

c++ - 将字符串指针与 NULL 以及 NULL 字符进行比较的目的

c++ - 为什么我在 std::map 上使用 Operator[] 无效?

c++ - 在 C++17 中调用对象生命周期之外的非静态成员函数

c++ - 在 C++ 中使用 UTF-8 字符串正确检查回文