c++ 什么是std::views::计数?

3zwtqj6y  于 2022-12-05  发布在  其他
关注(0)|答案(3)|浏览(218)

https://en.cppreference.com/w/cpp/ranges上,std::views::count列在范围适配器部分中。但是,它未标记为范围适配器对象。
我猜这就是为什么我不能使用管道操作符来编写的原因:

std::vector<size_t> vec = {1, 2, 3, 4, 5};
auto view = vec | std::ranges::counted(... ; // does not compile

我的问题是:

  • 什么是**std::ranges::count?**为什么它列在range adapter部分?
  • 使用案例是什么?使用takedrop有什么优势?
yhqotfr8

yhqotfr81#

Cppreference遵循C++20标准的组织结构,它把views::counted放到the "Range Adaptors" section中,尽管标准说:
可以链接这些适配器以创建范围变换的管道,这些管道在迭代结果视图时缓慢求值。
views::countedbehavior 并非如此。实际上,该节中的大多数其他元素都说它们的定制点“表示一个范围适配器对象”(描述管道功能),但views::counted does not除外。
不清楚为什么要把它放在那一节,但它本身就是一个有用的类型。它实际上只是一种表达subrange(it, it + n)的有效方式。它的有效性在于它实际上并不以n递增迭代器。
take_view相比,它的优势在于take_view对一个范围进行操作,而counted所需要的只是一个迭代器。take_view将为您提供 * 最多 * n个对象,但如果范围小于此值,(如标记所定义),它不会尝试迭代超出范围的结尾。

hpcdzsge

hpcdzsge2#

根据the docs
计数视图提供了对于某个迭代器i和非负整数n的计数范围[i,n)的元素的视图。
计数范围[i,n)是从i所指向的元素开始直到但不包括++i的n次应用的结果所指向的元素(如果有的话)的n个元素。
所以本质上,它返回一个切片,给定一个起始迭代器和在该迭代器之后要包含的一些元素。

#include <ranges>
#include <iostream>
 
int main()
{
    const int a[] = {1, 2, 3, 4, 5, 6, 7};
    for(int i : std::views::counted(a, 3))
        std::cout << i << ' ';
    std::cout << '\n';
 
    const auto il = {1, 2, 3, 4, 5};
    for (int i : std::views::counted(il.begin() + 1, 3))
        std::cout << i << ' ';
    std::cout << '\n';
}

输出量
比较您列出的特定函数,以下是它们的摘要:

  • std::ranges::views::take:由另一个视图的前N个元素(最多)组成的视图
  • std::ranges::views::drop:由另一个视图的元素组成的视图,跳过(最多)前N个元素
  • std::ranges::views::counted:从迭代器和计数创建一个子范围,始终正好包含N个元素
hmae6n7t

hmae6n7t3#

views::counted类似于views::take,但是前者接受迭代器而不是范围。
views::counted相对于views::take的一个优点是,它允许我们在已知大小的情况下构建一个 sized 输入/输出范围:

auto ints = views::istream<int>(std::cin);

auto counted = views::counted(ints.begin(), 4);
auto take    = views::take(ints, 4);

static_assert(ranges::sized_range<decltype(counted)>); // ok
static_assert(ranges::sized_range<decltype(take)>);    // failed

views::take不同,由于我们省略了sentinel信息,我们必须确保迭代器在n次递增后仍然有效,而前者保证总是返回有效的范围。

相关问题