我有一个自定义数据结构,可以通过多种方式访问。我想尽可能保持这个数据结构符合STL标准。所以我已经有很多typedef,它给模板参数提供STL名称。现在这对我来说一切照旧。
但是我不太确定如何正确地将迭代器添加到我的数据结构中。我面临的主要问题是,数据结构上会有多个迭代策略。最简单的用例是遍历所有元素,这些元素可以通过数据结构上的STL-Conforming迭代器很好地处理。然而,人们可能还想访问元素,这些元素在某种程度上类似于给定的键。我还想以一种可以与STL接口的方式迭代所有这些相似的元素。
这些是我到目前为止所考虑的想法:
这基本上是std::map
的作用。子范围的开始和结束迭代器由std::map::lower_bound()
和std::map::upper_bound()
提供。
但是这很有效,因为begin()
,end()
,lower_bound()
和upper_bound()
返回的迭代器是兼容的,即operator==()
可以给出一个在这些上有非常明确的含义。在我看来,这很难做到,或者甚至不可能给出一些明确的语义。例如,我可能会遇到it1==it2
但++it1!=++it2
的情况。我不确定STL是否允许这样做。
提供干净的operator==()
语义要容易得多。另一方面令人讨厌,因为它扩大了类型的数量。
我不确定这是否可行。迭代状态应该由迭代器以某种方式保存(直接或在Memento中)。使用这种方法意味着专门化所有stl :: algorithms并直接在特化中访问谓词。很可能是不可能的,如果可能的话,也是一个非常糟糕的主意。
现在我主要选择版本1,即根本不提供一种类型的迭代器。但是,由于我不清楚如何清理语义,我还没有决定。
你会如何处理?
答案 0 :(得分:3)
为什么更多类型出现问题?它并不一定意味着更多的代码。例如,您可以使迭代器键入一个模板,该模板将迭代策略作为模板参数。然后,迭代策略可以提供迭代的实现:
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;
}
您可能必须使iterator-types的迭代策略类成为朋友。
答案 1 :(得分:2)
标准容器支持两种迭代策略,包含两种迭代器类型:::iterator
和::reverse_iterator
。您可以使用std::reverse_iterator
的构造函数及其成员函数base()
在两者之间进行转换。
根据迭代策略的相似程度,向不同的迭代器类型提供转换可能也可能不容易。我们的想法是结果应该指向目标类型的迭代策略中的“等效位置”。对于反向迭代器,这个等价是通过说如果在该点插入,结果是相同的来定义的。因此,如果rit
是反向迭代器,vec.insert(rit.base(), ...)
在反向迭代中“rit
之前插入一个元素,也就是说之后> em>容器中rit
指向的元素。这非常繁琐,只有在迭代策略完全不相关时才会变得更糟。但是如果你的所有迭代器类型都是(或者可以看起来像)围绕所有元素的“普通”迭代器的包装器,那么你可以根据底层迭代器位置定义转换。
如果有成员函数添加或删除容器的元素,那么实际上只需要需要转换,因为您可能不希望为每个迭代器类型提供单独的重载(就像标准容器没有为反向迭代器定义insert
和erase
。如果迭代器仅用于指向元素,那么很可能没有它们。
如果不同的迭代策略都是按照正常顺序在元素的子集上进行迭代,那么请查看boost::filter_iterator
。
我可能会遇到
it1==it2
但++it1!=++it2
的情况。我是 不确定STL是否允许这样做。
如果我理解正确,您从it1
开始thing.normal_begin()
,从it2
开始获得thing.other_policy_begin()
。标准容器没有定义比较属于不同范围的相同类型的迭代器的结果,所以如果你确实使用了一个普通类型,那么我认为这样就好了,前提是文档清楚地说明了{{1}确实有效,范围根据迭代器的来源分开。
例如,您可以使用operator==
作为构造函数参数,每次调用skip_iterator
时它应该向前移动的步数。然后,您可以在比较中包含该整数,以便++
,或者您可以将其排除在thing.skip_begin(1) != thing.skip_begin(2)
但thing.skip_begin(1) == thing.skip_begin(2)
之外。我认为如果有文件记载,或者你可以证明比较它们是UB,除非它们来自同一个起点。