c++20范围的意义是什么

What is the point of c++20 ranges?

本文关键字:是什么 范围 c++20      更新时间:2024-09-24

与传统迭代器相比,我很难理解c++20范围添加了什么。是的,我想不再需要使用beginend,而是简单的重载,例如:

namespace std {
template <typename Container>
auto transform(Container&& container, auto&&... args) requires ( requires {container.begin(); container.end(); }) {
return transform(container.begin(), container.end(), args...);
}
}

会解决这个问题。

为什么范围有用?与迭代器相比,我应该在什么时候使用它们?

编辑:我知道范围比迭代器还有其他优势(链接、更好的方法等(。然而,这些(我认为?(都可以用迭代器来完成,我不明白为什么需要引入一个全新的概念,比如范围。

您反对自己的结论,如下所示:

template <typename Container>
auto transform(Container&& container, auto&&... args)
requires ( requires {container.begin(); container.end(); }) {

所以。。。这是什么?它是一个采用满足约束的模板参数的函数。让我们忽略这个约束需要成员begin/end,而不是更合理的std::ranges::begin/end要求。

您将对多少功能应用此要求?可能很多。每个算法都会有一个版本有这个要求。所以这看起来不像是一次性的要求,更像是应该命名为concept的东西。

特别是因为这个概念可能应该指定算法需要什么样的迭代器。你不只是需要会员begin/end;您需要它们返回一个input_or_output_iterator和一个迭代器:的sentinel_for

requires ( requires(Container c)
{
{c.begin()} -> input_or_output_iterator;
{c.end()} -> sentinel_for<decltype(c.begin())>;
})

你真的想每次你要求一个";集装箱";?当然不是;这就是命名概念的作用。

那么这个概念是什么呢?它是一个可以迭代的东西,一个可以通过特定迭代器接口访问的值序列。

该概念的名称可能应该选择为不意味着对元素序列的所有权。transform算法并不关心给定的是否拥有序列。所以"容器";绝对是个错误的名字。

因此,让我们将这个概念称为范围值序列。值序列可以通过迭代器/sentinel接口进行迭代。您可能需要有不同类别的值序列。输入序列、前向序列、连续序列等。您可能想检测序列是否可以在恒定时间内计算大小,或者序列是有界的还是从其所有者那里借来的。

如果您能编写运算符来创建这些值序列的视图,这不是很好吗?

任何其他名字的炉灶闻起来都一样甜。一旦你开始走迭代器和哨兵配对的黑暗道路,它将永远主宰你的命运。

在处理迭代器时,范围是一个自然的概念。所有建立在范围概念之上的东西都是它的产物。

大多数标准库核心概念(如迭代器(的目的是统一标准库中常见的抽象。对于迭代器,这意味着为"this指向容器中的元素,我们希望能够在容器上迭代"这一常用概念提供一个接口。

因此,范围的意义在于对公共用户界面隐藏原始迭代器。迭代时,我们经常需要2个指针;容器的起点和终点。Ranges试图通过隐藏这个接口来简化这一点,并为在begin((和end((之间操作的函数提供一个单独的接口。

特别是,范围视图将是使用范围的主要原因。当您想要进行函数组合时,它们允许更容易地读取代码。cppreference中的示例是一个很好的示例用法:

#include <ranges>
#include <iostream>

int main()
{
auto const ints = {0,1,2,3,4,5};
auto even = [](int i) { return 0 == i % 2; };
auto square = [](int i) { return i * i; };

// "pipe" syntax of composing the views:
for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
std::cout << i << ' ';
}

std::cout << 'n';

// a traditional "functional" composing syntax:
for (int i : std::views::transform(std::views::filter(ints, even), square)) {
std::cout << i << ' ';
}
}

与原始迭代器相比,范围和视图以接近零的成本提供了更高级别的抽象层。在我个人看来,特别是与使用没有范围的c++编写的代码相比,"视图管道"更易于阅读和维护。