C++20 带来了更强大的 iterator系统,其中之一是引入iterator_concept
基于iterator_category
.
我发现iterator_concept
和 iterator_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_concept
和 iterator_category
正确吗?是否iterator_category
在 C++20 中还有意义吗?
最佳答案
C++17 (C++98) 迭代器模型和 C++20 Ranges 迭代器模型之间存在不向后兼容的差异。两个大的是:
reference
即 value_type&
或 value_type const&
. 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
,而不仅仅是那样)。准则:
std::iterator_traits<I>::iterator_category
. std::meow_iterator
概念 iterator_category
别名并确保您遵循前向迭代器/引用限制(或...不要,但它在您身上)iterator_category
进行了很好的描述。和 iterator_concept
类型别名。 关于c++ - C++20 中的 iterator_category 和 iterator_concept 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67606563/