2017-11-29 6 views
0

私は反復したいタイプ "T"のオブジェクトのコレクションを持っています。タイプ「T」の対象は、2つの重要なプロパティがあります。C++用のカスタムイテレータ関数

int r; // row number 
int c; // column number 

私は私がコレクションのすべての要素を反復処理することを可能にする反復子を定義したいと思います。

これは、使用して行うことができます。

std::vector<T> v; 

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) { 
    .... 
} 

しかし、私は1つの以上の特性を持っているイテレータをしたいと思います。私は、この関数を呼び出すと、V ER + 1 = ec.rとECがで指さ現在の要素であるEC = ec.c、の要素「e」を返す必要があります

it.nextrow() 

を呼び出すことができるようにしたいと思いますイテレータ私。 it.nextrow()を呼び出すと、columnが同じである行が1つ増えた要素へのポインタが返されます。それが理にかなってほしい。

私は先進的なC++の概念をかなり新しくしているので、これが機能するためには何が必要なのかよくわかりません。誰か助けてくれますか?

+0

データの構造をより詳しく説明できますか?私は 'std :: vector 'と 'int r、c'の関係を見ていません。各行に列の値の集まりがある行オブジェクトのベクトルを持っていますか、または行のすべての列がベクトル内で次々に来るフラットなレイアウトを持っていますか? – grek40

答えて

2

すべてがメンバー関数である必要はありません。無料でiterator nextRow(iterator current, iterator begin, iterator end)を受け取りますか?

template<typename Iterator> 
Iterator nextRow(Iterator needle, Iterator begin, Iterator end) 
{ 
    return std::find_if(begin, end, [needle](const T & elem) { return (elem.r == needle->r + 1) && (elem.c == needle->c); }); 
} 

ベクトルが常にソートされている場合は、別のbeginを使用する必要はありません。needleを使用してください。

ラッパー・イテレーターの一部である必要がある場合は、そのタイプにはbeginとendを入れる必要があります。

template <typename Iterator> 
class SearchableIterator 
{ 
    Iterator wrapped, begin, end; 
public: 
    difference_type  Iterator::difference_type; 
    value_type   Iterator::value_type; 
    pointer    Iterator::pointer; 
    reference   Iterator::reference 
    iterator_category Iterator::iterator_category 

    SearchableIterator(Iterator wrapped, Iterator begin, Iterator end) 
     : wrapped(wrapped), begin(begin), end(end) {} 

    // All the members, calling that member of wrapped (see std::reverse_iterator for guidance) 

    SearchableIterator nextRow() 
    { 
     return SearchableIterator(std::find_if(begin, end, [this](const T & elem) { return (elem.r == wrapped->r + 1) && (elem.c == wrapped->c); }), begin, end); 
    } 
} 
+0

私は自分のインターフェースが修正されたコードの一部を実装しています。したがって、それをit.nextrow()の形式で使用できるようにする必要があります。これは可能ですか? –

+0

はい、メンバーを 'std :: vector :: iterator'に追加することはできません。あなたはラッパーを書く必要があります。 nextRow関数と同じデータが必要です。 – Caleth

0

イテレータはコピー可能です。

あなたは

  • は、あなたの余分な財産のメンバーを追加
  • 、それは(開始宣言し、コンテナのイテレータから建設を追加
  • 、あなたのコンテナのコンテナのイテレータから導き出すことができ、あなたのカスタムコンテナからのend()などは派生イテレータを返します。あなたのデータを想定し
0

は、次の行の項目に続く行のすべての列の連続した項目をベクトルにパックされて、あなただけの次の行に同じ列の値(ドン」にアクセスする*(iterator + column_count)が必要になります

template<typename T, int colsize, typename TIterator = std::vector<T>::iterator> 
class MyRowIterator : public std::iterator<std::forward_iterator_tag, T> 
{ 
private: 
    TIterator m_pter; 
public: 

    MyRowIterator(TIterator& value): m_pter(value) 
    { 
    } 
    MyRowIterator(const MyRowIterator& other_it): m_pter(other_it.m_pter) 
    { 
    } 
    MyRowIterator& operator++() 
    { 
     ++m_pter; 
     return *this; 
    } 
    bool operator!=(const MyRowIterator& rhs) 
    { 
     return m_pter != rhs.m_pter; 
    } 
    T& operator*() 
    { 
     return (*m_pter); 
    } 
    // here it is 
    T& nextrow() 
    { 
     return *(m_pter+colsize); 
    } 
}; 

使用例:Tなどの追加情報をカウントあなたはImplement custom iterator for c++ std containerに似たラッパーイテレータを作成し、それを特定の列を与えることができ、既にデータの最後の行に向いていますイテレータ)

でこれを試してみてください。

void Test() 
{ 
    std::vector<int> data; 

    // 2 rows each 10 columns 
    data.resize(20); 
    for (auto& item : data) 
    { 
     item = 0; 
    } 
    data[2] = 1; 
    data[12] = 5; 

    // don't iterate the last line, else nextrow() will access out of bounds! 
    for (MyRowIterator<int, 10> iter = data.begin(); iter != (data.end()-10); iter++) 
    { 
     std::cout << *iter << " # " << iter.nextrow() << std::endl; 
    } 
} 
関連する問題