C20带来了更强大的iterator系统,其中之一就是在iterator_category
的基础上引入了iterator_concept
。
我发现C20中很多迭代器的iterator_concept
和iterator_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
不一致。
C20为什么要引入iterator_concept
?它的目的是什么?如果我实现了自己的迭代器,如何正确定义iterator_concept
和iterator_category
?iterator_category
在C20中仍然有意义吗?
1条答案
按热度按时间x7rlezfr1#
C17(C98)迭代器模型和C++20 Ranges迭代器模型之间存在不向后兼容的差异。这两个大问题是:
reference
是value_type&
或value_type const&
。contiguous
迭代器。最强的类别是random_access
。(1)的结果是相当重要的-它意味着如果你有一个返回纯右值的迭代器(无论是否是代理引用),它永远不会比输入迭代器更强。因此,
views::iota(1, 10)
尽管很容易就能支持随机访问,但充其量只是一个C98输入范围。但是,你不能只是...取消这一要求。假设C98迭代器并使用
iterator_category
进行判断的现有代码完全有权假设如果iterator_category
是bidirectional_iterator_tag
,则其reference
是value_type
的某种左值引用。iterator_concept
所做的是添加一个新的C20层,允许迭代器既通告其C98/17类别,又明显地通告其C20类别。所以回到iota_view<int, int>
的例子,该视图的迭代器将iterator_category
设置为input_iterator_tag
(因为reference
是纯右值,所以它不满足偶数向前的旧要求),但其iterator_concept
设置为random_access_iterator_tag
(因为一旦我们放弃该限制,我们可以轻松支持所有随机访问限制)。在iterator.concepts.general(https://eel.is/cdraft/iterator.concepts.general)中,我们有一个神奇的函数
ITER_CONCEPT(I)
,它可以帮助我们确定在C20中使用什么标记。(2)的问题是,由于各种C++98/17代码会检查该标记的方式(许多代码可能会检查
random_access_iterator_tag
),因此很难添加新的contiguous_iterator_tag
。iterator_concept
方法还引入了一些概念,可以直接为您检查正确的事情(即,random_access_iterator
概念检查ITER_CONCEPT(I)
是从random_access_iterator_tag
派生而来的,而不是简单的那样)。指导原则:
std::iterator_traits<I>::iterator_category
。std::meow_iterator
概念iterator_category
别名,并确保你遵循前向迭代器/引用限制(或...不要,但这是你的)iterator_category
和iterator_concept
类型别名有很好的描述。