C ++中的自定义迭代器

时间:2009-05-08 14:10:52

标签: c++ stl iterator

我有一个类TContainer,它是指向TItems类的几个stl集合指针的集合。

我需要创建一个Iterator来遍历我的TContainer类中所有集合中的元素,从而抽象出内部工作的客户端。

这样做的好方法是什么?我应该创建一个扩展迭代器的类(如果是,我应该扩展什么迭代器类),我应该创建一个迭代器类,它是迭代器的集合吗?

我只需要一个FORWARD_ONLY迭代器。

I.E,如果这是我的容器:

typedef std::vector <TItem*> ItemVector;
class TContainer {
   std::vector <ItemVector *> m_Items;
};

遍历m_Items成员变量向量中包含的所有项目的好迭代器。

6 个答案:

答案 0 :(得分:31)

当我使用自己的迭代器(前一段时间)时,我继承自std :: iterator并将该类型指定为第一个模板参数。希望有所帮助。

对于前向迭代器,用户使用forward_iterator_tag而不是以下代码中的input_iterator_tag。

这个类最初来自istream_iterator类(并且我自己修改了它,因此它可能不再像istram_iterator那样)。

template<typename T>
class <PLOP>_iterator
         :public std::iterator<std::input_iterator_tag,       // type of iterator
                               T,ptrdiff_t,const T*,const T&> // Info about iterator
{
    public:
        const T& operator*() const;
        const T* operator->() const;
        <PLOP>__iterator& operator++();
        <PLOP>__iterator operator++(int);
        bool equal(<PLOP>__iterator const& rhs) const;
};

template<typename T>
inline bool operator==(<PLOP>__iterator<T> const& lhs,<PLOP>__iterator<T> const& rhs)
{
    return lhs.equal(rhs);
}

在迭代器标签上查看此文档:
http://www.sgi.com/tech/stl/iterator_tags.html

重新阅读有关迭代器的信息:
http://www.sgi.com/tech/stl/iterator_traits.html

这是旧的做事方式(iterator_tags)更现代的方法是设置iterator_traits&lt;&gt;为你的迭代器使它与STL完全兼容。

答案 1 :(得分:22)

如果您有权访问Boost,使用iterator_facade是最强大的解决方案,而且使用起来非常简单。

答案 2 :(得分:18)

首先让我们概括一下:

typedef int value_type;
typedef std::vector<value_type*> inner_range;
typedef std::vector<inner_range*> outer_range;

现在是迭代器:

struct my_iterator : std::iterator_traits<inner_range::iterator> 
{
    typedef std::forward_iterator_tag iterator_category;

    my_iterator(outer_range::iterator const & outer_iterator, 
                outer_range::iterator const & outer_end)
    : outer_iterator(outer_iterator), outer_end(outer_end)
    { 
        update();
    }

    my_iterator & operator++()
    {
        ++inner_iterator;
        if(inner_iterator == inner_end)
        {
            ++outer_iterator;
            update();
        }
        return *this;
    }

    reference operator*() const
    {   
        return *inner_iterator;
    }

    bool operator==(my_iterator const & rhs) const
    {   
        bool lhs_end = outer_iterator == outer_end;
        bool rhs_end = rhs.outer_iterator == rhs.outer_end;
        if(lhs_end && rhs_end)
            return true;
        if(lhs_end != rhs_end)
            return false;
        return outer_iterator == rhs.outer_iterator 
            && inner_iterator == rhs.inner_iterator;
    }

private:

    outer_range::iterator outer_iterator, outer_end;
    inner_range::iterator inner_iterator, inner_end;

    void update()
    {
        while(outer_iterator != outer_end)
        {
            inner_iterator = (*outer_iterator)->begin();
            inner_end = (*outer_iterator)->end();
            if(inner_iterator == inner_end)
                ++outer_iterator;
            else
                break;
        }
    }    
};

此类假定外部迭代器包含指向内部范围的指针,这是您的问题中的要求。这反映在update成员,begin()end()之前的箭头中。如果要在外部迭代器按值包含内部范围的更常见情况下使用此类,则可以用点替换这些箭头。注意BTW,这个类与内部范围包含指针的事实无关,只有类的客户端才需要知道。

如果我们使用boost::iterator_facade,代码可能会更短,但是没有必要为这么简单的事情添加一个boost依赖。此外,唯一棘手的部分是相等和增量操作,无论如何我们必须对它们进行编码。

我将以下的锅炉板成员留作“为读者练习”:

  • postfix increment iterator
  • 运算符!=
  • 默认构造函数
  • 操作符 - &GT;

另一项有趣的练习是将其转换为适用于任意容器的模板。除了必须在几个地方添加typename注释之外,代码基本相同。

使用示例:

int main()
{
    outer_type outer;
    int a = 0, b = 1, c = 2;
    inner_type inner1, inner2;
    inner1.push_back(&a);
    inner1.push_back(&b);
    inner2.push_back(&c);
    outer.push_back(&inner1);
    outer.push_back(&inner2);

    my_iterator it(outer.begin(), outer.end());
                e(outer.end(), outer.end());
    for(; it != e; ++it)
        std::cout << **it << "\n";
}

打印哪些:

  

0 1 2

答案 3 :(得分:6)

迭代器只是一个支持某个接口的类。至少,您希望能够:

  • 递增和/或递减
  • 取消引用它以使其“指向”
  • 的对象
  • 测试它是否存在平等和不平等
  • 复制并指定

一旦你有一个可以为你的集合明智地做这个的类,你将需要修改集合以具有返回迭代器的函数。至少你会想要

  • 一个begin()函数,它返回位于第一个元素
  • 的新迭代器类型的实例
  • 一个end()函数,它返回一个迭代器,该迭代器(可能是名义上的)位于容器中项目末尾的一个位置

答案 4 :(得分:1)

检查Views Template Library

特别检查

  1. Union View展示两个连接的容器。
  2. Concatenation View展示连接的容器集合。

答案 5 :(得分:0)

这是我能够生成的最简单的代码(用于自定义迭代器)。请注意,我才开始探索这个领域。这会调用内置的upper_bound函数来对整数函数x^2执行二进制搜索。

#include <algorithm>
#include <iostream>

using namespace std;

class Iter
{
  public:
  int x;
  Iter() { x = -1; }
  Iter(int a) { x = a; }

  bool operator!=(Iter &i2) const { return x != i2.x; }
  void operator++() { x++; }
  void operator+=(int b) { x += b; }
  int operator-(const Iter &i2) const { return x - i2.x; }
  int operator*() const {
    cout << "calculating for x " << x << endl;
    return x*x;
  }

  typedef random_access_iterator_tag iterator_category;
  typedef int value_type;
  typedef int difference_type;
  typedef int* pointer;
  typedef int& reference;
};

main ()
{
  ios::sync_with_stdio(false);
  cout << upper_bound(Iter(0), Iter(100), 40).x << endl;
}

// :collapseFolds=1:folding=explicit:

这就是输出的样子:

calculating for x 50
calculating for x 25
calculating for x 12
calculating for x 6
calculating for x 9
calculating for x 8
calculating for x 7
7