33

C++17 引入了 ContiguousIterator http://en.cppreference.com/w/cpp/iterator的概念。然而,似乎并没有计划让contiguous_iterator_tag(以我们现在的方式random_access_iterator_tag)报告std::iterator_traits<It>::iterator_category

为什么contiguous_iterator_tag失踪?

是否有传统的协议来确定迭代器是否是连续的?还是编译时测试?

过去我提到,对于容器,如果有一个.data()成员可以转换为::value类型指针,并且有.size()成员可以转换为指针差异,那么应该假设容器是连续的,但我无法提取迭代器的类似特性.

一种解决方案可能是还具有data用于连续迭代器的功能。

当然 Contiguous 概念适用&(it[n]) == (&(*it)) + n于 , for all n,但这不能在编译时检查。


编辑:我发现这个视频将其置于更广泛的 C++ 概念背景中。CppCon 2016: Patrick Niedzielski撰写的“在现代多核世界中构建和扩展迭代器层次结构” 。该解决方案使用概念(Lite),但最终的想法是连续迭代器应该实现一个pointer_from函数(与我的data(...)函数相同)。

结论是概念将有助于将理论形式化,但它们并不是魔法,因为某人、某处将在连续的迭代器上定义新的特别命名的函数。该演讲概括为分段迭代器(具有相应的函数segmentlocal),不幸的是它没有提及跨步指针。


编辑 2020:

现在标准有

struct contiguous_iterator_tag: public random_access_iterator_tag { };

https://en.cppreference.com/w/cpp/iterator/iterator_tags

4

1 回答 1

23

原始答案

基本原理在N4284中给出,它是连续迭代器提案的采用版本:

本文介绍了术语“连续迭代器”作为随机访问迭代器的改进,但没有引入相应的contiguous_iterator_tag,在 Nevin Liber 的论文 N3884“连续迭代器:随机访问迭代器的改进”的 Issaquah 讨论中发现它会破坏代码。

一些代码被破坏了,因为它假定std::random_access_iterator无法改进,并对其进行了明确的检查。基本上它破坏了不依赖多态性来检查迭代器类别的错误代码,但它仍然破坏了代码,因此std::contiguous_iterator_tag从提案中删除。

此外,std::reverse_iterator-like 类还有一个额外的问题:反向连续迭代器不能是连续迭代器,而是常规随机访问迭代器。这个问题本来可以解决的std::reverse_iterator,但是更多用户定义的迭代器包装器在复制迭代器类别的同时扩充迭代器,要么撒谎要么停止正常工作(例如 Boost 迭代器适配器)。

C++20 更新

由于我上面的原始答案std::contiguous_iterator_tag被带回 Ranges TS,然后在 C++20 中采用。为了避免上面提到的问题,std::iterator_traits<T>::iterator_category没有改变的行为。相反,用户std::iterator_traits现在可以定义一个额外的iterator_concept成员类型别名,允许别名std::contiguous_iterator_tag或以前的迭代器标签。标准组件已相应更新,以便将指针和适当的迭代器标记为连续的迭代器。

该标准定义了一个仅用于说明的ITER_CONCEPT(Iter),给定一个迭代器类型,如果它存在Iter则将别名,否则。没有等效的标准面向用户的类型特征,但新的迭代器概念使用了ITER_CONCEPT 。这是一个强烈的提示,您应该使用这些迭代器概念而不是旧式标记调度来实现其行为取决于迭代器类别的新函数。上述概念可用作布尔特征,因此您可以简单地检查迭代器是否为连续迭代器,如下所示:std::iterator_traits<Iter>::iterator_conceptstd::iterator_traits<Iter>::iterator_category

static_assert(std::contiguous_iterator<Iter>);

std::contiguous_iterator因此,您应该使用 C++20 概念来检测给定的迭代器是随机访问迭代器(它也有对应的范围:)std::contiguous_range。值得注意的是,std::contiguous_iterator除了要求ITER_CONCEPT匹配之外,它还有一些额外的约束std::contiguous_iterator_tag:最值得注意的是,它需要std::to_address(it)是返回原始指针类型的有效表达式。是一个小型实用函数,旨在避免在尝试检索连续迭代器指向的地址时可能发生的一些陷阱 - 您可以在Helpful pointers forstd::to_address中阅读有关它解决的问题的更多信息 。ContiguousIterator

于 2017-03-17T10:56:00.657 回答