c++20 范围的意义是什么? [已关闭]

问题描述 投票:0回答:2

我很难理解 c++20 范围与老式迭代器相比增加了什么。是的,我想不再需要使用

begin
end
,但是简单的重载例如:

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

可以解决这个问题。

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

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

c++ iterator c++20 std-ranges
2个回答
9
投票

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

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

 算法并不关心给定的内容是否拥有该序列。所以“容器”这个名字绝对是错误的。

所以我们称这个概念为

范围值序列。值序列可以通过迭代器/哨兵接口进行迭代。您可能需要有不同类别的值序列。输入序列、前向序列、连续序列等。您可能想检测序列是否可以在恒定时间内计算出大小,或者序列是否有界或从其所有者那里借用。

如果您可以编写创建这些值序列视图的运算符,岂不是很整洁?

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

范围是处理迭代器时的一个自然概念。基于范围概念构建的一切都是其产物。


4
投票
大多数标准库核心概念(例如迭代器)的目的是统一标准库中常见的抽象。对于迭代器,这意味着为常用概念“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++ 编写的代码相比,“视图管道”更易于阅读且更易于维护。

© www.soinside.com 2019 - 2024. All rights reserved.