2


0

抽象クラスの高速で柔軟なイテレータ

データを使用してグリッドを高速かつ柔軟にトラバースするために、抽象的なテンプレート化されたGridDataStructureクラスを設定しました。 データには、STLイテレータがアクセスする必要があります。 誰かがクラスを使用する場合、特定のサブクラスに適したSTLイテレータの種類について心配するべきではありません。

この問題の解決策はhttps://stackoverflow.com/questions/2191724/using-iterators-to-hide-internal-container-and-achieve-generic-operation-over-ab [イテレータを使用して内部コンテナを非表示にする]基本コンテナでの汎用操作を実現します]。 ただし、begin()およびend()メンバーが仮想ではなくなった理由はわかりません。 その次に、STLイテレータクラスに必要なメソッド(operator ++、operator *など)を正確に実装する必要がある場所を把握できませんでした。

デザインを間違えたかどうか見てください。 私にとって重要なのは、柔軟な設計ですが、パフォーマンスを犠牲にすることではありません。

私のクラスの設計:

template
class GridDataStructure
{
public:
    virtual iterator begin() = 0;
    virtual iterator end() = 0;
};

template
class GridDataUniform : GridDataStructure
{
public:
    GridDataUniform(int size);

    iterator begin();
    iterator end();

    class iterator : public std::iterator {
    public:
      iterator(Node* p) : node_(p) {}
      ~iterator() {}

      iterator& operator=(const iterator& other);
      bool operator==(const iterator& other);
      bool operator!=(const iterator& other);
      iterator& operator++();
      iterator& operator++(int);
      T& operator*();
      T* operator->();

    private:
      Node* node_;
    };

    private:
        T* griddata;
};

次のように、STLスタイルでグリッドコンテナにアクセスしたいと思います。

GridDataStructure::iterator = someGrid->begin(); // where someGrid is an instance of GridDataUniform
std::cout << *(iter) << std::endl;

任意の助けは大歓迎です。

編集(19.10.10):ネストされたイテレータークラスを追加

編集(20.10.10):追加されたコード:

template
class GridDataStructureBase
{
protected:
class BaseIteratorImpl
{
    virtual iterator begin() = 0;
    virtual iterator end() = 0;
    virtual iterator& operator++() = 0;
}

public:
class iterator : std::iterator
{
public:
    iterator(const BaseIteratorImpl& itImpl) {}
    iterator begin() { return itImpl->begin(); }
    iterator end() { return itImpl->end(); }
    iterator& operator++() { return itImpl->operator++() }

private:
    BaseIteratorImpl* itImpl;

};

iterator begin()
{
    iterator* i = new iterator(??);
    return i->begin();
}

iterator end()
{
    return iterator(NULL);
}

};

1 Answer


4


ソリューションでは、beginとendは仮想である必要はありません。仮想である `BaseIteratorImpl

begin`と` BaseIteratorImpl :: end`を呼び出すだけだからです。

特定のケースでは、「begin」と「end」を仮想化するだけで、転送は行わずに、必要な処理を実行できます。 あなたが指摘した解決策は、あなたが望むように見える構造とイテレータのペアだけでなく、同じ構造上に異なるスタイルのイテレータが必要な場合です。

編集:ここでは、(テストされていない、またはコンパイルされていない)開始するものがあります-コンパイルされず、リークする可能性があります(デストラクタを書き込み、ctorをコピーし、op =、必要な場所)-アイデアを始めるためだけに。

template
class GridIteratorImplBase {
   public:
      virtual GridIteratorImplBase& operator++() = 0;
      virtual T& operator*() = 0;
};

template
class GridIterator {
   private:
      GridIteratorImplBase *baseImpl;
   public:
      GridIterator(GridIteratorImplBase *b) :baseImpl(b) {}
      GridIterator& operator++() { baseImpl->operator++(); return *this;}
      T& operator*() { return baseImpl->operator*(); }


  // you need to write a dtor, copy ctor and op= or this will leak
  // copy ctor and op= need to make new objects that are copies of baseImpl, dtor needs to delete -- make sure not to share baseImpl between two GridIterator objects
};


template
class Grid {
   virtual GridIterator begin() = 0;
   virtual GridIterator end() = 0;
};


template
class GridUniform {

  template
  class GridUniformIterator : GridIteratorImplBase
      private T* current;
   public:
      GridUniformIterator(T* c) : current(c) {}
      virtual GridIteratorImplBase& operator++() { current++; return *this; }
      virtual T& operator*() { return *current; }
  };

  GridIterator begin() {
      GridIterator iter(new GridUniformIterator(gridData));
      return iter;
  }
  GridIterator end() {
      GridIterator iter(new GridUniformIterator(gridData+size));
      return iter;
  }


  private:
    T* gridData;
    int size;
};

コンパイラではなく、この回答のテキスト領域に直接入力しました。 それはあなたが始めることができるようにあなたにアイデアを与えることを意図しています。

  1. beginとendはイテレータを作成することになっています

  2. 反復子は、コピーを構築し、operator =を持つことができる必要があります 彼らに呼ばれた。 それらに1つの基底クラスを持たせようとすると、基底にキャストされるため、それらに仮想クラスを使用することはできません。

  3. #2を回避するには、イテレータが イテレータ実装の基本クラス。