链接C ++的迭代器

时间:2009-06-11 13:48:01

标签: c++ iterator

Python的itertools实现了一个chain迭代器,它基本上连接了许多不同的迭代器,以提供单个迭代器的所有东西。

C ++中有类似的东西吗?快速浏览一下boost库并没有发现类似的东西,这对我来说非常令人惊讶。是否难以实现此功能?

7 个答案:

答案 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页面:

视图是容器适配器,它提供

的容器接口
  1. 部分数据或
  2. 重新安排数据或
  3. 转换数据或
  4. 数据集的合适组合
  5. 底层容器。由于视图本身提供容器界面,因此可以轻松地组合和堆叠它们。由于模板技巧,视图可以使其接口适应底层容器。更复杂的模板技巧使这个强大的功能易于使用。

    与智能迭代器相比,视图只是智能迭代器工厂。

答案 6 :(得分:0)

据我所知,在实现此功能的boost中没有任何功能 - 我进行了相当广泛的搜索。

我认为我上周很容易实现这一点,但我遇到了一个问题:Visual Studio 2008附带的STL,当启用范围检查时,不允许比较来自不同容器的迭代器(即,你可以不要将somevec1.end()与somevec2.end()进行比较。突然间,实现这一点变得更加困难,我还没有决定如何去做。

我过去使用了iterator_facade和iterator_adapter来编写其他迭代器,这比编写'raw'迭代器更好但我仍然觉得用C ++编写自定义迭代器比较麻烦。

如果有人可以发布一些伪代码来说明如何完成/不使用/比较来自不同容器的迭代器,我会非常感激。

相关问题