過小評価イテレータ

これは、標準のSTLテンプレートライブラリに関するものです。 既存のタイプのイテレーターとその分類が考慮され、イテレーターのいくつかの新しいラッパーが提案されます。 これにより、C ++ 11以前のようにラムダ式を回避できる場合があります。



はじめに



このライブラリの主なパラダイムの1つは、2つのエンティティの分離でした。 コンテナとアルゴリズム。 ただし、コンテナデータに対するアルゴリズムの直接的な影響のために、中間エンティティであるイテレータを導入する必要がありました。



反復子により、アルゴリズムは、コンテナのタイプに関係なく、コンテナに含まれるデータにアクセスできます。 ただし、このためには、各コンテナでイテレータクラスを定義する必要がありました。 このようにして、アルゴリズムは、コンテナの内部表現を認識しているイテレータを介してデータに作用します。



STLのイテレーターのタイプ



特定のコンテナのデータにアクセスするイテレータに加えて、STLライブラリにはさらにいくつかのイテレータがあります。

1. back_insert_iteratorおよびfront_insert_iterator

2. insert_iterator

3. istream_iteratorおよびostream_iterator



タイプback_insert_iteratorおよびfront_insert_iteratorのイテレーターは、コンテンツを変更するときに、push_back()またはpush_front()メソッドを使用して要素を挿入します。 これらのイテレータは、コンテナの前/次の要素に移動する操作を単に無視します。



insert_iteratorイテレータは、変更されるとデータを挿入します。 コンテナとイテレータは、データを挿入する位置でコンストラクタに渡されます。



istream_iteratorおよびostream_iteratorイテレーターは、ストリームからデータを読み取り、ストリームにデータを書き込みます。 これらの反復子の設計者は、入力または出力ストリームを渡す必要があります。



イテレータの分類



イテレーターの既存の分類には、イテレーターの5つのカテゴリーがあります。

1.入力イテレーター

2.出力イテレーター

3.前方反復子

4.双方向イテレーター

5.ランダムアクセスイテレーター



異なるカテゴリに属する​​イテレータには、有効な操作の異なるセットがあります。 操作は次のように分類されます。

イテレータカテゴリ 特徴 有効な表現
すべてのカテゴリ 画像にコピーして作成できます X b(a);

b = a;
1つ増やすことができます ++ a

++

* ++
ランダムアクセス 双方向 進む 入力 平等/不等比較をサポート a == b

a!= b
取得するために 右辺値としてのみ逆参照できます * a

a-> m
出力 割り当て記号の左側で使用する左辺値として逆参照される場合があります * a = t

* a ++ = t
コピーして、繰り返しトラバーサルに使用できます。 X a(b);

++ a == ++ b
1つ減らすことができます --a

a--

* a--
算術演算をサポート+および- a + n

n + a

a-n

a-b
反復子間の比較(<、>、<=および> =)をサポート a <b

a> b

a <= b

a> = b
操作の増加をサポート+ +および減少-= a + = n

a-= n
インデックスによる逆参照をサポート([]) [n]


イテレータデコレータの開発



以下のいくつかのアイデアを実装するには、ラッパーまたはデコレータ( wrapper )を実装する必要がありました。 イテレータデコレータには、ラップされるイテレータと同じカテゴリが必要です。つまり、同じメソッドセットを提供します。 上記のカテゴリの表に従って開発されました:

1.交差しないメソッドセットを実装する5つのミックスインクラス。

2.イテレータカテゴリによってパラメータ化されたテンプレートデコレータクラス。

3. 混合不純物のセットによって特徴付けられるテンプレートの5つの専門化。

4.便利な(明示的なテンプレートパラメータなしの)イテレータラッピングのファクトリ。

[このコードはこちらでご覧いただけます 。ほとんど機能します]



結果として得られた構造を1人の優秀な人物と簡単に議論した後、新しい構造が開発されました。 テンプレートでそれほど飽和しておらず、より簡潔です。 反復子カテゴリによってパラメータ化された1つのテンプレートクラスに、反復子のすべてのカテゴリのすべてのメソッドを実装することが決定されました。 次のC ++言語プロパティが使用されました。実際に呼び出されるテンプレートクラスのメソッドのみがコンパイルされます。



したがって、入力カテゴリのイテレータをラップする必要がある場合、入力カテゴリに属する​​メソッドのみがコンパイルされ呼び出されます。 このカテゴリに属さないメソッドを呼び出そうとすると、コンパイルエラーが発生します。 そして、これはまさに私たちが目指していたものです。



ビット反復子



ビット反復子を使用すると、コンテナ要素を少しずつバイパスできます。 反復子は、ビット値の読み取りと書き込みの両方に使用できます。 反復子にはパラメーターがあります。

1.コンテナ要素のバイトをバイパスする順序

2.バイト単位のビットをバイパスする順序



使用例:

{ // 00001010 00001011 00001010 00001011 // * * * ** * * * ** char input[] = "\x0A\x0B\x0A\x0B"; char * input_ptr = input; int a = std::count(bit_walker(input_ptr), bit_walker(input_ptr+4), 1); EXPECT_EQ(2 + 3 + 2 + 3, a); }
      
      





フィールド反復子



フィールドイテレータは、参照解除されると、構造体のフィールドの1つの値を返すイテレータです。 いずれかのフィールドの値からオブジェクトを見つけるのに非常に役立ちます。 使用例:



 { // What to find: [200] "puper" // // {100,"hello"} // {200,"super"} => {200,"super"} // {300,"puper"} => {300,"puper"} struct ABC { int value; std::string str; }; ABC input[] = { {100,"hello"}, {200,"super"}, {300,"puper"} }; ABC * input_ptr = input; int a = std::find(field_walker(input_ptr, fieldof(ABC,value)), field_walker(input_ptr+3, fieldof(ABC,value)), 200) - input_ptr; int b = std::find(field_walker(input_ptr, fieldof(ABC,str)), field_walker(input_ptr+3, fieldof(ABC,str)), "puper") - input_ptr; EXPECT_EQ(1, a); EXPECT_EQ(2, b); }
      
      







マクロfieldof(クラス、フィールド)は次のとおりです。



 #define fieldof(Object,field) (&(((Object*)NULL)->field))
      
      





UPD

ユーザーmayorovpが指摘したように、クラスフィールドへのポインターで取得できます。



 &Object::field
      
      







ソートイテレーター



ソート反復子は、ソート順で要素を走査する反復子です。 コンテナ要素は、イテレータトラバース中に変更されません 。 この場合の利点は、並べ替えにかかる時間が無駄にならないことです(並べ替えに割り当てられる時間の特定のセクションがありません)。



反復子が次の要素に移動すると、残りの要素のうち、前の要素以上の最小要素を検索します。 したがって、アルゴリズムの複雑さはO(N 2 )ですが、並べ替えに割り当てられる特別な時間はありません。 ソートは、データにアクセスするプロセスで実行されます。 イテレータは段階的に処理されます-ソートも段階的です。



反復子は、ソート順でパラメーター化されます。 デフォルト:昇順で並べ替え。



使用例:

 { // A:{ 5,2,1,2,2 } => A:{ 5,2,1,2,2 } // B:{ 0,0,0,0,0 } => B:{ 5,2,2,2,1 } int input[5] = { 5,2,1,2,2 }; int output[5] = { 0,0,0,0,0 }; int * input_ptr = (int *)input; int * output_ptr = (int *)output; std::copy(sorter<Descending>(input_ptr,input_ptr+5), sorter<Descending>(input_ptr+5), output_ptr); // Expect input EXPECT_EQ(5, input[0]); EXPECT_EQ(2, input[1]); EXPECT_EQ(1, input[2]); EXPECT_EQ(2, input[3]); EXPECT_EQ(2, input[4]); // Expect output EXPECT_EQ(5, output[0]); EXPECT_EQ(2, output[1]); EXPECT_EQ(2, output[2]); EXPECT_EQ(2, output[3]); EXPECT_EQ(1, output[4]); }
      
      





注:



1.イテレータのカテゴリの表は、ここから引用されています(いくつかのバグが見つかりました-ソースサイトにエラーが通知されます ): http : //www.cplusplus.com/reference/std/iterator/

2.お気づきの方も多いと思いますが、コード例はGoogle C ++ Testing Frameworkのテストです。つまり、コードはリポジトリにあり、テストがあります。 バグを見つけたら-それを明らかにするテストを書いてください))これはコード全体のある場所です: http : //code.google.com/p/stliw/コードに関するコメントは登録せずに残すことができます-ようこそ。



PS

この記事は6ヶ月前に私が書いたものです。 今日、私はそれをほぼ完全な状態で見つけて公開しました。 彼女がなぜ私のドラフトで6か月を費やしたのかを言うのは難しい。 いずれにせよ、何かを完成またはリメイクしたかったのかもしれません。



All Articles