【问题标题】:Creating my own Iterators创建我自己的迭代器
【发布时间】:2010-09-13 23:52:42
【问题描述】:

我正在努力学习 C++,如果这个问题表明缺乏基础知识,请原谅我,你看,事实是,我缺乏基础知识。

我需要一些帮助来解决如何为我创建的类创建迭代器。

我有一个“形状”类,它有一个点容器。 我有一个类'Piece',它引用了一个形状并定义了一个形状的位置。 Piece 没有 Shape,它只是引用一个 Shape。

我希望它看起来像 Piece 是一个 Points 容器,这些点与它引用的 Shape 相同,但添加了 Piece 位置的偏移量。

我希望能够遍历 Piece 的点,就像 Piece 本身就是一个容器一样。我做了一些阅读,并没有找到任何对我有帮助的东西。如果有任何指点,我将不胜感激。

【问题讨论】:

  • 发布示例代码将有助于描述您正在做的事情,而不仅仅是简单的英文文本。
  • 创建自定义迭代器可能不是一个基本的顶部,至少是中间的。

标签: c++ iterator


【解决方案1】:

/EDIT:我明白了,这里实际上需要一个自己的迭代器(我首先误读了这个问题)。尽管如此,我还是保留下面的代码,因为它在类似的情况下很有用。


这里真的需要一个自己的迭代器吗?也许将所有必需的定义转发到包含实际点的容器就足够了:

// Your class `Piece`
class Piece {
private:
    Shape m_shape;

public:

    typedef std::vector<Point>::iterator iterator;
    typedef std::vector<Point>::const_iterator const_iterator;

    iterator begin() { return m_shape.container.begin(); }

    const_iterator begin() const { return m_shape.container.begin(); }

    iterator end() { return m_shape.container.end(); }

    const_iterator end() const { return m_shape.const_container.end(); }
}

这是假设您在内部使用vector,但可以轻松调整类型。

【讨论】:

  • 也许他想对他的类使用 STL 算法或功能特性...
  • 原来的问题确实说,片容器的迭代器在返回值时应该修改它们。这将需要一个单独的迭代器,尽管它可能应该主要从原始迭代器继承或以其他方式获得。
  • @gbjbaanb:我的代码的好处是它可以被 STL 算法使用。
  • 几年后,这仍然是谷歌搜索结果中的佼佼者......现在可以通过执行以下操作来概括这一点:auto begin() -&gt; decltype(m_shape.container.begin()) { return m_shape.container.begin(); }
【解决方案2】:

您应该使用 Boost.Iterators。它包含许多模板和概念,用于为现有的迭代器实现新的迭代器和适配器。我写了an article about this very topic;它在 2008 年 12 月的 ACCU 杂志上。它针对您的问题讨论了一个 (IMO) 优雅的解决方案:使用 Boost.Iterators 从对象公开成员集合。

如果您只想使用 stl,Josuttis book 有一章介绍如何实现您自己的 STL 迭代器。

【讨论】:

  • 只是一个小评论:这本书谈论的是 C++ 标准库,而不是 STL——它们是不同的,但很困惑(我也/曾经有罪)
【解决方案3】:

Designing a STL like Custom Container 是一篇优秀的文章,它解释了如何设计类似 STL 的容器类及其迭代器类的一些基本概念。反向迭代器(有点难)虽然留作练习:-)

HTH,

【讨论】:

    【解决方案4】:

    你可以阅读这个ddj article

    基本上,从 std::iterator 继承来为您完成大部分工作。

    【讨论】:

    • 请注意,std::iterator 在 C++17 中被标记为 deprecated
    【解决方案5】:

    用 C++ 编写自定义迭代器可能非常冗长且难以理解。

    由于我找不到编写自定义迭代器的最小方法,我写了this template header,这可能会有所帮助。例如,要使 Piece 类可迭代:

    #include <iostream>
    #include <vector>
    
    #include "iterator_tpl.h"
    
    struct Point {
      int x;
      int y;
      Point() {}
      Point(int x, int y) : x(x), y(y) {}
      Point operator+(Point other) const {
        other.x += x;
        other.y += y;
        return other;
      }
    };
    
    struct Shape {
      std::vector<Point> vec;
    };
    
    struct Piece {
      Shape& shape;
      Point offset;
      Piece(Shape& shape, int x, int y) : shape(shape), offset(x,y) {}
    
      struct it_state {
        int pos;
        inline void next(const Piece* ref) { ++pos; }
        inline void begin(const Piece* ref) { pos = 0; }
        inline void end(const Piece* ref) { pos = ref->shape.vec.size(); }
        inline Point get(Piece* ref) { return ref->offset + ref->shape.vec[pos]; }
        inline bool cmp(const it_state& s) const { return pos != s.pos; }
      };
      SETUP_ITERATORS(Piece, Point, it_state);
    };
    

    那么你就可以把它当作一个普通的 STL Container 来使用了:

    int main() {
      Shape shape;
      shape.vec.emplace_back(1,2);
      shape.vec.emplace_back(2,3);
      shape.vec.emplace_back(3,4);
    
      Piece piece(shape, 1, 1);
    
      for (Point p : piece) {
        std::cout << p.x << " " << p.y << std::endl;
        // Output:
        // 2 3
        // 3 4
        // 4 5
      }
    
      return 0;
    }
    

    它还允许添加其他类型的迭代器,例如 const_iteratorreverse_const_iterator

    希望对你有帮助。

    【讨论】:

      【解决方案6】:

      解决您的问题的方法不是创建您自己的迭代器,而是使用现有的 STL 容器和迭代器。将每个形状中的点存储在类似矢量的容器中。

      class Shape {
          private:
          vector <Point> points;
      

      从那时起,您要做什么取决于您的设计。最好的方法是遍历 Shape 内部方法中的点。

      for (vector <Point>::iterator i = points.begin(); i != points.end(); ++i)
          /* ... */
      

      如果您需要访问 Shape 之外的点(这可能是设计缺陷的标志),您可以在 Shape 中创建将返回点的迭代器访问函数的方法(在这种情况下,还要为点容器创建一个公共 typedef )。查看 Konrad Rudolph 的回答,了解这种方法的详细信息。

      【讨论】:

      • 他仍然需要创建自己的迭代器,将请求转发到 Piece 到该 Piece 中的 Shapes。自定义迭代器在这里是一个很棒的工具,而且使用起来非常优雅。
      猜你喜欢
      • 2014-08-08
      • 2013-08-19
      • 1970-01-01
      • 2010-12-16
      • 2016-01-23
      • 2015-02-12
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多