web-dev-qa-db-ja.com

C ++ 11 foreach構文とカスタムイテレータ

STLコンテナーの代わりに使用されているコンテナーのイテレーターを作成しています。現在、STLコンテナは c ++ 11 foreach構文 で多くの場所で使用されています。例:for(auto &x: C)。 STLコンテナをラップするカスタムクラスを使用するには、コードを更新する必要があります。

template< typename Type>
class SomeSortedContainer{
    std::vector<typename Type> m_data; //we wish to iterate over this
    //container implementation code
};    
class SomeSortedContainerIterator{
    //iterator code
};

コードを次の方法で呼び出すことができるように、カスタムコンテナの正しいイテレータを自動で使用するにはどうすればよいですか?

SomeSortedContainer C;
for(auto &x : C){
    //do something with x... 
}

一般に、autoがクラスに正しい反復子を使用することを保証するために何が必要ですか?

59
shuttle87

次の2つの選択肢があります。

  • beginおよびendという名前のメンバー関数を提供します。これらは、C.begin()およびC.end();のように呼び出すことができます。
  • そうでない場合は、beginおよびendという名前の無料の関数を提供します。これらの関数は、引数依存のルックアップを使用して、または名前空間stdで見つけることができ、begin(C)およびend(C)
51

範囲ベースのforを使用できるようにするには、クラスでconst_iterator begin() constおよびconst_iterator end() constメンバーを提供する必要があります。グローバルbegin関数をオーバーロードすることもできますが、私の意見では、メンバー関数を使用する方が適切です。 iterator begin()およびconst_iterator cbegin() constも推奨されますが、必須ではありません。単一の内部コンテナを繰り返し処理するだけの場合、それは非常に簡単です。

template< typename Type>
class SomeSortedContainer{

    std::vector<Type> m_data; //we wish to iterate over this
    //container implementation code
public:
    typedef typename std::vector<Type>::iterator iterator;
    typedef typename std::vector<Type>::const_iterator const_iterator;

    iterator begin() {return m_data.begin();}
    const_iterator begin() const {return m_data.begin();}
    const_iterator cbegin() const {return m_data.cbegin();}
    iterator end() {return m_data.end();}
    const_iterator end() const {return m_data.end();}
    const_iterator cend() const {return m_data.cend();}
};    

ただし、カスタムをイテレートする場合は、コンテナー内のクラスとして独自のイテレーターを設計する必要があります。

class const_iterator : public std::iterator<random_access_iterator_tag, Type>{
    typename std::vector<Type>::iterator m_data;
    const_iterator(typename std::vector<Type>::iterator data) :m_data(data) {}
public:
    const_iterator() :m_data() {}
    const_iterator(const const_iterator& rhs) :m_data(rhs.m_data) {}
     //const iterator implementation code
};

イテレータクラスの記述の詳細については、 my answer here を参照してください。

51
Mooing Duck

他の人が述べたように、コンテナはbegin()およびend()関数を実装する必要があります(または、コンテナのインスタンスをパラメータとして取るグローバルまたはstd::関数が必要です)。

これらの関数は同じ型を返す必要があります(通常はcontainer::iteratorですが、これは単なる規則です)。返される型は、operator*operator++、およびoperator!=を実装する必要があります。

7
dspeyer

私の知る限り、SomeSortedContainerbegin()end()を提供する必要があります。そして、これらは標準準拠のフォワードイテレータを返すはずです。あなたの場合はSomeSortedContainerIteratorで、実際にはstd::vector<Type>::iterator。標準準拠では、通常のインクリメント演算子と逆参照演算子を提供する必要がありますが、すべてのvalue_typereference_type、... typedefs。これは、コンテナ要素の基本型を決定するためにforeach構造体によって順番に使用されます。ただし、std::vector<Type>::iterator

2
Christian Rau