c++ - C++20 中的 iterator_category 和 iterator_concept 有什么区别?

标签 c++ iterator c++20 range-v3 std-ranges

C++20 带来了更强大的 iterator系统,其中之一是引入iterator_concept基于iterator_category .
我发现iterator_conceptiterator_category C++20 中的许多迭代器是不一致的。拿最有名的iota_view作为 example :

using R = decltype(views::iota(0));
static_assert(random_access_range<R>);

using I = ranges::iterator_t<R>;
static_assert(same_as<typename I::iterator_category, input_iterator_tag>);
static_assert(same_as<typename I::iterator_concept,  random_access_iterator_tag>);
虽然 R型号 random_access_range , iterator_category它的迭代器只是一个 input_iterator_tag ,这与 iterator_concept 不一致.
为什么C++20引入iterator_concept ?它的目的是什么?如果我实现自己的迭代器,我该如何定义 iterator_conceptiterator_category正确吗?是否iterator_category在 C++20 中还有意义吗?

最佳答案

C++17 (C++98) 迭代器模型和 C++20 Ranges 迭代器模型之间存在不向后兼容的差异。两个大的是:

  • C++98 模型要求前向迭代器具有 referencevalue_type&value_type const& .
  • C++98 模型不允许 contiguous迭代器。最强的类别是random_access .

  • (1) 的结果非常重要 - 这意味着如果您有一个返回纯右值的迭代器(无论是否代理引用),它永远不会比输入迭代器强。所以,views::iota(1, 10) ,尽管很容易支持随机访问,但充其量只是一个 C++98 输入范围。
    但是,您不能只是……取消此要求。假定 C++98 迭代器并使用 iterator_category 的现有代码做出判断完全在其权利范围内假设如果iterator_category例如,bidirectional_iterator_tag ,它的 reference是对 value_type 的某种左值引用.
    什么 iterator_concept添加一个新的 C++20 层,允许迭代器宣传其 C++98/17 类别,并且明显地宣传其 C++20 类别。所以回到 iota_view<int, int>例如,该 View 的迭代器具有 iterator_category设置为 input_iterator_tag (因为 reference 是一个纯右值,所以它不满足偶数转发的旧要求)但它的 iterator_concept设置为 random_access_iterator_tag (因为一旦我们取消该限制,我们就可以轻松支持所有随机访问限制)。
    [iterator.concepts.general] , 我们有这个神奇的功能 ITER_CONCEPT(I)这有助于我们确定在 C++20 中使用什么标签。
    (2) 的问题在于很难只添加一个新的 contiguous_iterator_tag之前由于各种 C++98/17 代码会检查该标签的方式(很多代码可能会准确检查 random_access_iterator_tag )。 iterator_concept方法通过引入直接为您检查正确事物的概念来避免这个问题(即 random_access_iterator 概念检查 ITER_CONCEPT(I) 派生自 random_access_iterator_tag ,而不仅仅是那样)。

    准则:
  • 如果您在 C++17 中使用迭代器,请使用 std::iterator_traits<I>::iterator_category .
  • 如果您在 C++20 中使用迭代器,请使用 std::meow_iterator概念
  • 如果您在 C++17 中编写迭代器,请添加 iterator_category别名并确保您遵循前向迭代器/引用限制(或...不要,但它在您身上)
  • 如果您使用 C++20 编写迭代器,请遵循 P2259 中的指导其中对问题以及如何以及何时提供 iterator_category 进行了很好的描述。和 iterator_concept类型别名。
  • 关于c++ - C++20 中的 iterator_category 和 iterator_concept 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67606563/

    相关文章:

    c++ - 从 C++ 中的类成员函数返回对象

    c++ - 在 Ubuntu 中使用 C/C++ 进行线路输入插孔感知

    python - 迭代器协议(protocol)。是黑魔法吗?

    java.util.ConcurrentModificationException,但我正在迭代副本,而不是正在修改的集合

    c++ - lambda 在 C++20 中使用此实体或具有自动存储持续时间的未捕获实体是否合法?

    c++ - 在 sqlite3 C++ 中批量插入的更好方法

    c++ - 将参数传递给基类构造函数时成员的初始化

    filter - 为什么在迭代器上使用过滤器时会得到不同的参数类型?

    c++ - 是否可以在 C++20 中使用比较运算符在枚举值之间建立小于大于大于的排序关系

    c++ - 可能违反严格的别名?