如何处理多个迭代器类型

How to handle multiple iterator types

本文关键字:迭代器 类型 处理 何处理      更新时间:2023-10-16

我有一个定制的数据结构,可以通过多种方式访问它。我希望尽可能保持这个数据结构符合stl标准。我已经有了很多类型定义,它们为模板参数提供了stl名称。到目前为止,这对我来说是家常便饭。

然而,我不确定如何正确地将迭代器添加到我的数据结构中。我面临的主要问题是,在数据结构上会有多个迭代策略。最简单的用例是遍历所有元素,这可以由符合stl的迭代器在数据结构上很好地处理。但是,也可能需要访问与给定键类似的元素。我还想以一种我可以与STL接口的方式迭代所有这些类似的元素。

这些是我目前为止考虑过的想法:

  • 只提供一种类型的迭代器:

这基本上是std::map所做的。子范围的开始迭代器和结束迭代器由std::map::lower_bound()std::map::upper_bound()提供。

然而,这工作得很好,因为begin(), end(), lower_bound()upper_bound()返回的迭代器是兼容的,也就是说,operator==()可以在这些迭代器上给出一个非常明确的含义。在我的情况下,这将很难得到正确的,或者甚至可能不可能给出一些明确的语义。例如,我可能会得到一些it1==it2++it1!=++it2的情况。我不确定STL是否允许这样做。

  • 提供多种类型的迭代器:

更容易提供干净的operator==()语义。另一方面,Nasty是因为它增加了类型的数量。

  • 提供一种类型的迭代器并使用stl::算法进行专门化访问

我不确定这是否可能。迭代器应该以某种方式(直接或在Memento中)保存迭代状态。使用这种方法意味着专门化所有stl::算法并在专门化中直接访问谓词。很可能不可能,如果可能的话,这是一个非常糟糕的主意。

现在我主要选择版本1,即只提供一种类型的迭代器。然而,由于我不清楚如何清理语义,我还没有决定。

你会如何处理这种情况?

标准容器支持两种迭代策略,具有两种迭代器类型:::iterator::reverse_iterator。您可以使用std::reverse_iterator的构造函数及其成员函数base()在两者之间进行转换。

根据迭代策略的相似程度,提供到不同迭代器类型的转换可能很容易,也可能不容易。其思想是,结果应该指向目标类型的迭代策略中的"等效位置"。对于反向迭代器,这种等价的定义是,如果在该点插入,结果是相同的。因此,如果rit是反向迭代器,则vec.insert(rit.base(), ...)在逆向迭代中插入一个元素"在"rit 之前,也就是说,在容器中rit所指向的元素之后插入元素。这是非常繁琐的,并且只会在迭代策略完全不相关时变得更糟。但是,如果所有的迭代器类型都是(或者看起来像是)遍历所有元素的"普通"迭代器的包装器,那么就可以根据底层迭代器的位置定义转换。

实际上只有在存在添加或删除容器元素的成员函数时才需要转换,因为您可能不希望必须为每种迭代器类型提供单独的重载(就像标准容器没有为反向迭代器定义inserterase一样)。如果迭代器仅用于指向元素,那么很可能不需要它们。

如果不同的迭代策略都在元素的子集上以正常顺序迭代,则查看boost::filter_iterator

我可能会得到一些it1==it2++it1!=++it2的情况。我是不确定STL是否允许。

如果我理解正确的话,你从thing.normal_begin()开始得到it1,从thing.other_policy_begin()开始得到it2。标准容器没有定义比较属于不同范围的相同类型的迭代器的结果,所以如果您确实使用了公共类型,那么我认为这将是好的,只要文档明确说明尽管operator==确实有效,但范围是根据迭代器的来源分开的。

例如,可以有一个skip_iterator,它将每次调用++时应该向前移动的步数作为构造函数参数。然后你可以在比较中包含这个整数,这样thing.skip_begin(1) != thing.skip_begin(2),或者你可以排除它,这样thing.skip_begin(1) == thing.skip_begin(2)但是++(++(thing.skip_begin(1))) == ++(thing.skip_begin(2))。我认为只要有文档就可以,或者你可以证明比较它们是UB,除非它们来自相同的起点。

为什么类型多是个问题?这并不一定意味着更多的代码。例如,您可以创建一个迭代器类型的模板,该模板将迭代策略作为模板参数。然后迭代策略可以提供迭代的实现:

struct iterate_all_policy {
    iterate_all_policy(iterator<iterate_all_policy> & it) : it(it) {}
    void advance() { /* implement specific advance here */ }
private:
    iterator<iterate_all_policy> & it;
}

您可能必须将迭代策略类设置为迭代器类型的朋友。