5

以下代码适用于 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);

我得到了这个编译器错误:

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,但我不知道它到底是什么,有人可以帮忙吗?

4

1 回答 1

6

std::ranges::make_heapuses std::ranges::less,它有一个约束:

与 不同std::lessstd::ranges::less要求所有六个比较运算符<<=>>===!=有效(通过totally_ordered_with约束)。

您的类型S没有相等运算符;spaceship 运算符仅提供其他比较运算符。*

要解决此问题,operator==请为您的类型提供一个:

constexpr auto operator==(const S& s) const {
  return i == s.i;
}

神螺栓链接: https ://godbolt.org/z/cGfrxs

*operator<=>并不意味着operator==出于性能原因,因为operator==可以短路集合而operator<=>不能。但是,从https://en.cppreference.com/w/cpp/language/default_comparisons中,我们看到 defaultedoperator<=>也将隐式默认 an 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我们的类型。std::ranges::lessvalue_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,这意味着是时候为这个概念和 for 编写文档了std::ranges::less

于 2020-11-06T04:45:13.960 回答