Python的itertools实现了一个chain迭代器,它基本上连接了许多不同的迭代器,以提供单个迭代器的所有东西。
C ++中有类似的东西吗?快速浏览一下boost库并没有发现类似的东西,这对我来说非常令人惊讶。是否难以实现此功能?
答案 0 :(得分:20)
在调查类似问题时遇到了这个问题。
即使问题很老,现在在C ++ 11和boost 1.54的时候,使用Boost.Range库也很容易。它具有join
-function,可以将两个范围连接成一个范围。在这里你可能会产生性能损失,因为最低的公共范围概念(即Single Pass Range or Forward Range等)被用作新范围的类别,并且在迭代期间可以检查迭代器是否需要跳转到新范围,但是您的代码可以轻松编写如下:
#include <boost/range/join.hpp>
#include <iostream>
#include <vector>
#include <deque>
int main()
{
std::deque<int> deq = {0,1,2,3,4};
std::vector<int> vec = {5,6,7,8,9};
for(auto i : boost::join(deq,vec))
std::cout << "i is: " << i << std::endl;
return 0;
}
答案 1 :(得分:4)
在C ++中,迭代器通常在范围的开始和结束的上下文之外没有意义。迭代器本身不知道起点和终点在哪里。所以为了做这样的事情,你需要将迭代器的范围链接在一起 - range是一对(开始,结束)迭代器。
查看boost::range文档。它可以提供构建范围链的工具。一个区别是它们必须是相同的类型并返回相同类型的迭代器。进一步可以进一步通用,将不同类型的范围链接在一起,例如any_iterator,但也许不是。
答案 2 :(得分:2)
我之前写了一个(实际上,只是将两对迭代器链接在一起)。这并不难,特别是如果你使用boost iterator_facade
。
创建输入迭代器(实际上是Python的chain
所做的)是一个简单的第一步。为迭代器查找链接不同迭代器类别组合的正确类别留给读者练习; - )。
答案 3 :(得分:2)
你实际上正在寻找的是一个外观迭代器,它通过几个序列抽象出来。
由于你来自python背景我会假设你更关心灵活性而不是速度。灵活性我的意思是能够链接迭代不同的序列类型(向量,数组,链表,集等等),而速度我的意思是只从堆栈中分配内存。
如果是这种情况,那么您可能需要查看adobe labs中的any_iterator: http://stlab.adobe.com/classadobe_1_1any__iterator.html
此迭代器将使您能够在运行时迭代任何序列类型。链接你将有一个3元组any_iterators的向量(或数组),即你链接在一起的每个范围的三个any_iterator(你需要三个向前或向后迭代,如果你只想向前迭代两个就足够了)。
假设您希望对整数序列进行链式迭代:
(未经测试的伪代码c ++代码)
typedef adobe :: any_iterator AnyIntIter;
struct AnyRange { AnyIntIter开始; AnyIntIter curr; AnyIntIter结束; };
您可以定义范围,例如:
int int_array [] = {1,2,3,4}; AnyRange sequence_0 = {int_array,int_array,int_array + ARRAYSIZE(int_array)};
然后,您的RangeIterator类将具有std :: vector。
<code>
class RangeIterator {
public:
RangeIterator() : curr_range_index(0) {}
template <typename Container>
void AddAnyRange(Container& c) {
AnyRange any_range = { c.begin(), c.begin(), c.end() };
ranges.push_back(any_range);
}
// Here's what the operator++() looks like, everything else omitted.
int operator++() {
while (true) {
if (curr_range_index > ranges.size()) {
assert(false, "iterated too far");
return 0;
}
AnyRange* any_range = ranges[curr_range_index];
if (curr_range->curr != curr_range->end()) {
++(curr_range->curr);
return *(curr_range->curr);
}
++curr_range_index;
}
}
private:
std::vector<AnyRange> ranges;
int curr_range_index;
};
</code>
但我想注意这个解决方案非常慢。更好的,更像C ++的方法只是存储你想要操作的对象的所有指针并迭代它。或者,您可以将仿函数或访问者应用于您的范围。
答案 4 :(得分:1)
不在标准库中。 Boost可能会有所作为。
但实际上,这样的事情应该是微不足道的。只需使用迭代器向量作为成员,使自己成为迭代器。一些非常简单的运算符++代码,你就在那里。
答案 5 :(得分:1)
检查Views Template Library (VTL)。它可能没有直接提供'链式迭代器'。但我认为它具有可用于实现您自己的“链式迭代器”的所有必要工具/模板。
来自VTL页面:
视图是容器适配器,它提供
的容器接口底层容器。由于视图本身提供容器界面,因此可以轻松地组合和堆叠它们。由于模板技巧,视图可以使其接口适应底层容器。更复杂的模板技巧使这个强大的功能易于使用。
与智能迭代器相比,视图只是智能迭代器工厂。
答案 6 :(得分:0)
据我所知,在实现此功能的boost中没有任何功能 - 我进行了相当广泛的搜索。
我认为我上周很容易实现这一点,但我遇到了一个问题:Visual Studio 2008附带的STL,当启用范围检查时,不允许比较来自不同容器的迭代器(即,你可以不要将somevec1.end()与somevec2.end()进行比较。突然间,实现这一点变得更加困难,我还没有决定如何去做。
我过去使用了iterator_facade和iterator_adapter来编写其他迭代器,这比编写'raw'迭代器更好但我仍然觉得用C ++编写自定义迭代器比较麻烦。
如果有人可以发布一些伪代码来说明如何完成/不使用/比较来自不同容器的迭代器,我会非常感激。