C++返回方法,用于分块列表后找不到子范围

7eumitmz  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(130)

我遇到了一个奇怪的行为,如果你创建一个列表的分块视图,由2个元素组成,然后在一个范围for循环中尝试打印前面和后面,前面的方法可以工作,但后面的方法不行。它会产生一个编译器错误,说示例化.back()方法需要一个双向迭代器。我错过了什么吗?

重现错误的代码

#include <iostream>
#include <list>
#include <ranges>
#include <vector>

int main() {
  std::list<int> nums_list = {0, 1, 2, 3, 4, 5};

  auto rng = nums_list | std::views::chunk(2);
  for (auto pair : rng) {
    std::cout << pair.front(); // Front will work normally
    std::cout << pair.back();  // No matching member function for 'back'.
  }
}

字符串
我也用vector试过了,效果和预期的一样。

j7dteeu8

j7dteeu81#

它将产生一个编译器错误,说明示例化.back()方法需要一个双向迭代器。
仅当从view_interface继承的视图满足forward_range时才提供front()成员,并且如果common_rangebidirection_range都满足,则提供back()成员。
std::list满足common_rangebidirectional_range,所以rng也是common_rangebidirectional_range †,这允许你在上面使用back(),例如:

std::list<int> nums_list = {0, 1, 2, 3, 4, 5};
auto rng = nums_list | std::views::chunk(2);
auto back = rng.back();

字符串
然而,rng的值类型,即示例中的pair,被指定为decltype(views::take(subrange(current_, end_), n_)) †,其中current_end_std::list的迭代器。
由于std::list::iterator不能相减,也就是说它们不满足sized_sentinel_for,这使得它们构造的subrange不是sized_range,最终导致take_view不是common_range,所以它的back()合成失败。
†为了支持back()chunk_view还需要知道底层范围的大小,以找到最后一个块的起始位置。这对std::list来说不是问题,因为它是sized_range
<$views::take用于自动处理最后一个块的数量小于n的情况。

相关问题