14

ゲームの連続ループで移動したいオブジェクトがあります。std::vectorウェイポイントとして使用したい一連の座標があります。

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

私が思い付くことができる最善の方法は、2 つのイテレータを用意し、最初のイテレータが使い果たされるたびに、2 番目のイテレータの値を代入することです (これは他のことには使用されません)。代入演算子は、反復子がインデックスを保持するために使用しているものをコピーしますか、それとも単に参照されるだけですか (したがって、2 回目のラウンドの後は役に立たなくなります)。

オブジェクトがウェイポイントを永遠に移動するようにしたいのですが (オブジェクトが破棄されたが、そのメソッドでそれが起こらない場合を除きます)、イテレータはフレームごとに 1 回だけ呼び出され、ゲーム内の他のオブジェクトを更新できるように戻る必要があります。 .

ソリューションは、gcc および Microsoft コンパイラで動作する必要があります (標準の C++ で記述できない場合)。

4

3 に答える 3

23

さて、あなたの問題はより明確になりました:-)

boost::iterator_facade と boost::iterator アダプターを見てください。それらは完全なイテレータ インターフェイスcycle_iteratorを実装し、increment()、decrement() などのいくつかのメソッドを実装するだけです。

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は、いくつかの関数に関して完全なイテレータ インターフェイスを実装します。基本クラスに渡された基本反復子を使用して、、、、、およびのデフォルトの実装を提供しますincrement()decrement()advance()distance_to()equal_to()dereference()iterator_adaptor

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

于 2009-11-23T10:27:49.057 に答える
8

boost::iterator adaptor行く方法です、私の言葉を信じてください;)

そうは言っても、いくつかの落とし穴を指摘したいと思います。既存の回答を編集できるとは思わないので、ご容赦ください。

基本反復子がベクトルになることを考えると、どのコア インターフェイス関数を実装する必要があるかに注意する必要があります。ランダム アクセス イテレータにしたい場合cycle_iteratorは、次のすべてが必要です。

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

Nowdistance_to(j)は a のややおかしな概念でありcycle_iterator、そのセマンティクスはあらゆる種類のトラブルに巻き込まれる可能性があります。これは、適合イテレータのイテレータ カテゴリを順方向または双方向に制限することで回避できます。このような:

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

この場合、インクリメントを実装するだけで済みます。

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

双方向の場合、デクリメントも必要です。

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

免責事項:私はこれをコンパイラで実行していないので、恥ずかしい思いをする準備ができています.

于 2009-11-23T18:58:28.810 に答える
-4

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

ウェブ上にはたくさんのチュートリアルがあります。たとえば、このブログ記事を見てください。

于 2009-11-23T10:42:48.453 に答える