2009-11-23 17 views
13

私はゲームで連続したループで旅行したいオブジェクトを持っています。私はstd::vectorの座標系をウェイポイントとして使用したいと思っています。環状イテレータ(サーキュレータ)を作成する最も簡単な方法は?

std::vector<T>::iteratorサイクリック(サーキュレータとも呼ばれます)を行う方法はありますか?

私が思いつくのは、2つのイテレータを持つことです。そして、最初のイテレータが使い果たされると、それに2番目の値を代入します(これは他に何もしません)が、私はそれも確信していません代入演算子は、イテレータがインデックスを保持するために使用しているものをコピーするか、単に参照される(したがって、2番目のラウンド後には役に立たない)でしょうか?

オブジェクトがウェイポイントを永遠に移動するようにしたい(破壊されない限り、そのメソッドでは起こらない)が、反復子はフレームごとに1回だけ呼び出され、他のものゲーム内のオブジェクト。

解決策は、gccおよびmicrosoftコンパイラ(標準C++で記述できない場合)で動作する必要があります。

+0

私はそのようなイテレータを書いていますので、間違いなく可能です=) 唯一の覚えがあるのは、比較演算子<はイテレータが等しい場合を除いて常に真を返すことです。 –

+0

一方、本当に 'operator <'が必要ですか?サイクリックビヘイビアを隠すのはちょっといたずらです! –

答えて

21

今あなたの問題は、ブーストを見てみましょう

:-)明確で、[OK]を:: iterator_facadeはブースト::イテレータアダプタを。彼らは完全なイテレータインターフェイスを実装し、あなたのcycle_iteratorだけインクリメントのようないくつかのメソッド()、デクリメント()を実装するよう:

template<class IteratorBase> 
class cycle_iterator 
    : public boost::iterator_adaptor< 
      cycle_iterator,  // the derived class overriding iterator behavior 
      IteratorBase,  // the base class providing default behavior 
      boost::use_default, // iterator value type, will be IteratorBase::value_type 
      std::forward_iterator_tag, // iterator category 
      boost::use_default // iterator reference type 
     > 
{ 
    private: 
    IteratorBase m_itBegin; 
    IteratorBase m_itEnd; 

    public: 
    cycle_iterator(IteratorBase itBegin, IteratorBase itEnd) 
     : iterator_adaptor_(itBegin), m_itBegin(itBegin), m_itEnd(itEnd) 
    {} 

    void increment() { 
     /* Increment the base reference pointer. */ 
     ++base_reference(); 

     /* Check if past-the-end element is reached and bring back the base reference to the beginning. */ 
     if(base_reference() == m_itEnd) 
      base_reference() = m_itBegin; 
    } 

    // implement decrement() and advance() if necessary 
    }; 

をこれはおそらくコンパイルされませんが、あなたが始める必要があります。

編集:

boost::iterator_adaptorは、いくつかの機能の面で完全なイテレータインターフェイスを実装しています。 iterator_adaptor基本クラスに渡された基本イテレータを使用して、increment(),decrement(),、、equal_to()およびdereference()のデフォルトの実装を提供します。

必要なのは順方向イテレータだけです。increment()メソッドのみを実装して、最後のイテレータに到達したらラップアラウンドする必要があります。同様の方法でdecrement()を実装すると、循環型イテレータは双方向になります。 IteratorBase自体がランダムアクセスイテレータである場合、サイクルイテレータはランダムアクセスでもよく、メソッドadvanceおよびdistance_toはモジュロ演算を使用して実装する必要があります。

+0

+1: 'iterator_adaptor'はイテレータを書く最も簡単な方法です。例は素晴らしいです(特にアダプタを1つしか書いてconstとnon-constの両方のバージョンを取得する方法) –

+0

バイナリ演算子を作成する方法はありますか'!='は、 'cycle_iterator 'と 'IteratorBase'型の引数で動作しますか?私は 'cycle_iterator'と'通常の 'イテレータを比較しようとしています。この場合、明示的なオーバーロードをする必要があります。 – Mikhail

+1

'increment()'は仕事が必要です。私は理想的には、 'end'の前に値をインクリメントすると' begin'が得られるはずです。循環的イテレータの 'end'ではありません。 – Yakk

-5

std :: vectorから独自のコレクションを派生させ、インクリメント&のデクリメント演算子をオーバーライドする独自のイテレータ実装を提供します。

ウェブ上には多くのチュートリアルがあります。例えば、this blog post

+3

はベクトルから派生していますか?あなたはこれまで何かしたことがありますか?同意しません。代わりに集計する! – xtofl

+0

私は、標準コンテナから派生したクラスを見たことがありませんでした。集計。 –

+1

コメントに同意します。応答は早急に掲載され、余暇には悔い改めます。ただし、回答として受け入れられているため、削除できません。 –

7

boost::iterator adaptorを見に行くための方法です取る、それは私の言葉を取る;)

私はいくつかの落とし穴を指摘したい言われていること。私は既存の答えを編集することはできないと思うので、私に同行してください。

基本反復子がベクトルになるとすれば、実装する必要があるコアインタフェース関数に注意する必要があります。

increment() 
decrement() 
advance(n) 
distance_to(j) 

今すぐdistance_to(j)cycle_iteratorのため多少面白いコンセプトであり、その意味は、トラブルのすべての種類であなたを得ることができます:あなたはあなたのcycle_iteratorは、ランダムアクセスイテレータになりたい場合は、以下のすべてを必要とします。これは、適合イテレータのイテレータカテゴリを順方向または双方向に制限することによって回避できます。

void decrement() 
{ 
    if (this->base_reference() == this->m_itBegin) 
    { 
    this->base_reference() = this->m_itEnd; 
    } 
    --this->base_reference(); 
} 

は免責事項:私はを介してこれを実行しなかったあなたも減少を必要とする双方向について

void increment() 
{ 
    if (++this->base_reference() == this->m_itEnd) 
    { 
    this->base_reference() = this->m_itBegin; 
    } 
} 

:あなただけの増分を実装する必要がある。この場合

template <class BaseIterator> 
class cycle_iterator 
    : public boost::iterator_adaptor< 
     cycle_iterator     // Derived 
     , BaseIterator     // Base 
     , boost::use_default    // Value 
     , boost::forward_traversal_tag // CategoryOrTraversal 
    > 
{ ... }; 

:このようにコンパイラなので、私は恥ずかしい準備ができています。

+0

一般に、 'distance_to(j)'は正または負の数値を返すことができると思います。イテレータに追加すると、 'j'を指すイテレータが生成されます。このような数値が負でないか、絶対値が最も小さい数値のいずれかを返すことにします。ほとんどの場合、後者はおそらく最も理にかなっているか、そうでなければ強い反論がある(反例)か? –

関連する問題