独自のイテレーターを作成する


141

私はC ++を習得しようとしているので、この質問が基本的な知識の欠如を示している場合は許してください。

私が作成したクラスのイテレータを作成する方法を理解するための助けが欲しい。

ポイントのコンテナーを持つクラス 'Shape'があります。Shapeを参照し、Shapeの位置を定義するクラス「Piece」があります。ピースはシェイプを持たず、シェイプを参照するだけです。

ピースがポイントのコンテナのように見えるようにしたいのですが、それは参照するシェイプと同じですが、ピースの位置のオフセットが追加されています。

ピースがコンテナそのものであるかのように、ピースのポイントを反復処理できるようにしたい。私は少し読んでみましたが、私を助けてくれるものは何も見つかりませんでした。私はどんなポインタにもとても感謝しています。


6
サンプルコードを投稿することで、単純な英語のテキストよりも優れている点を説明できます。
グレッグロジャース

3
カスタムのイテレータを作成することは、おそらく基本的なトップではなく、少なくとも中間的なものです。
ldog

回答:


41

Boost.Iteratorsを使用する必要があります。これには、新しいイテレータと既存のイテレータ用のアダプタを実装するためのテンプレートと概念が多数含まれています。私はこのまさにこのトピックについての記事を書きまし。それは2008年12月のACCUマガジンにあります。それは正確にあなたの問題のための(IMO)エレガントなソリューションについて議論します:Boost.Iteratorsを使用してオブジェクトからメンバーのコレクションを公開します。

stlのみを使用したい場合、Josuttisの本には、独自のSTLイテレーターの実装に関する章があります。


3
ほんのマイナーな発言:この本はSTLではなくC ++標準ライブラリについて語っています-これらは異なりますが、かなり混乱します(私も罪があります)
CppChris

62

/編集:なるほど、実際にはここに独自のイテレータが必要です(最初に質問を読み間違えました)。それでも、以下のコードは同様の状況で役立つため、そのままにしておきます。


ここに独自のイテレータが実際に必要ですか?おそらく、必要なすべての定義を実際のポイントを保持するコンテナに転送するだけで十分です。

// 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

2
元の質問では、ピースコンテナのイテレータが値を返すときに値を変更する必要があると実際に言っています。おそらくそれは継承されるか、そうでなければほとんどがオリジナルから取得されるべきですが、それは別個のイテレータを必要とするでしょう。
workmad3 2008

@gbjbaanb:私のコードの良いところは、STLアルゴリズムで使用できることです。
Konrad Rudolph

1
数年後、これはまだグーグルのトップの結果の一つです...次のようなことをすることでこれを一般化することが可能になりました:auto begin() -> decltype(m_shape.container.begin()) { return m_shape.container.begin(); }
user2962533


15

あなたはこのddjの記事を読むことができます

基本的に、std :: iteratorから継承して、ほとんどの作業を完了させます。


2
std::iteratorはC ++ 17から非推奨とマークれていることに注意してください。
mandrake

2

C ++でカスタムイテレータを作成することは、非常に冗長で理解しにくい場合があります。

カスタムイテレータを作成するための最小限の方法が見つからなかったので、このテンプレートヘッダーを作成すると役立つ場合があります。たとえば、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コンテナとして使用できます。

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_iteratorまたはのような他のタイプのイテレータを追加することもできますreverse_const_iterator

お役に立てば幸いです。


1

問題の解決策は、独自のイテレーターを作成することではなく、既存のSTLコンテナーとイテレーターを使用することです。各シェイプのポイントをベクターのようなコンテナーに格納します。

class Shape {
    private:
    vector <Point> points;

それ以降に何をするかは、デザインによって異なります。最善のアプローチは、Shape内のメソッドのポイントを反復処理することです。

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

Shapeの外部のポイントにアクセスする必要がある場合(これは設計の欠陥の可能性があります)、ポイントの反復子アクセス関数を返すShapeメソッドで作成できます(その場合、ポイントコンテナーのパブリックtypedefも作成します)。このアプローチの詳細については、Konrad Rudolphの回答をご覧ください。


3
それでも、ピースへのリクエストをそのピースに含まれるシェイプに転送する独自のイテレータを作成する必要があります。カスタムイテレータはここでは優れたツールであり、非常にエレガントに使用できます。
Roel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.