【问题标题】:what are the constraints for std::ranges::make_heap?std::ranges::make_heap 的约束是什么?
【发布时间】:2021-02-18 20:20:30
【问题描述】:

以下代码适用于 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 的要求,但我不知道具体是什么,有人可以帮忙吗?

【问题讨论】:

  • 在错误消息中找到预期的重载,并查看针对该重载详细说明的失败约束。

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


【解决方案1】:

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

std::less 不同,std::ranges::less 要求所有六个比较运算符 &lt;&lt;=&gt;&gt;===!= 都有效(通过 totally_ordered_with 约束) .

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

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

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

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

* operator&lt;=&gt; 出于性能原因并不暗示 operator==,因为 operator== 可以短路集合,而 operator&lt;=&gt; 不能。但是,从 https://en.cppreference.com/w/cpp/language/default_comparisons 中,我们看到默认的 operator&lt;=&gt; 也将隐式默认 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。对向量的value_type 重复此错误消息调查std::ranges::less 会产生:

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 的文档了。

【讨论】:

  • 添加== 确实解决了这里的问题,但我认为解释不正确。例如如果&lt;=&gt; 是默认的,则为works
  • @cigien 实际上,宇宙飞船操作符的工作方式与我想象的有点不同,如果它是默认的,它会提供一个operator==。来自en.cppreference.com/w/cpp/language/default_comparisons :“如果operator&lt;=&gt; 是默认的,而operator== 根本没有声明,那么operator== 是隐式默认的。”
  • 啊,不错。我认为这解释了它:) 你可能想提一下。类似“因为你有一个非默认的&lt;=&gt;,所以不会生成==”。
猜你喜欢
  • 2020-01-11
  • 2021-12-15
  • 2021-09-29
  • 2020-09-22
  • 2021-10-01
  • 2021-05-11
  • 1970-01-01
  • 2022-12-15
  • 1970-01-01
相关资源
最近更新 更多