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

What is the difference between iterator_category and iterator_concept in C++20?

C++20带来了更强大的iterator系统,其中之一就是在iterator_category的基础上引入了iterator_concept

我发现C++20中很多迭代器的iterator_conceptiterator_category不一致。把最著名的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_categoryiterator_category 在 C++20 中还有意义吗?

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

  1. C++98 模型要求前向迭代器有一个 reference,即 value_type&value_type const&
  2. C++98 模型不允许 contiguous 迭代器。最强类别是 random_access.

(1) 的结果非常重要——这意味着如果您有一个 returns 纯右值的迭代器(无论代理引用与否),它永远不会比输入迭代器强。因此,views::iota(1, 10),尽管很容易支持随机访问,但充其量只是一个 C++98 输入范围。

但是,您不能只是...删除此要求。假设 C++98 迭代器并使用 iterator_category 进行判断的现有代码完全有权假设如果 iterator_categorybidirectional_iterator_tag,那么它的 reference是对 value_type.

的某种左值引用

iterator_concept 所做的是添加一个新的 C++20 层,该层允许迭代器既宣传其 C++98/17 类别,又明确地宣传其 C++20 类别。因此回到 iota_view<int, int> 示例,该视图的迭代器已将 iterator_category 设置为 input_iterator_tag(因为 reference 是纯右值,因此它不满足偶数的旧要求forward) 但它的 iterator_concept 设置为 random_access_iterator_tag (因为一旦我们放弃该限制,我们就可以轻松支持所有随机访问限制)。

[iterator.concepts.general] 中,我们有这个神奇的函数 ITER_CONCEPT(I) 可以帮助我们找出在 C++20 中使用什么标签。

(2) 的问题在于,由于各种 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 别名并确保遵循前向 iterator/reference 限制(或者......不,但它在你身上)
  • 如果您正在编写 C++20 中的迭代器,请遵循 P2259 中的指南,其中对问题以及如何以及何时进行了很好的描述提供 iterator_categoryiterator_concept 类型别名。