[C++] イテレータ with ループカウンタ

 イテレータで反復処理を行うとき、ループカウンタとりたい時ってあるじゃないですか。vectorならイテレータ同士の引き算で位置が求まりますが、なんかアレな気がしないですか。しないですか。そうですか。でもランダムアクセスイテレータだったらdistance使わなきゃないじゃないですか。いいですか。そうですか。もういっその事別にループカウンタ用の変数置けばいいじゃないですか。でもこれってなんか負けた感じがするんですよね…
 ということで今回は反復しつつカウンタの値も取るコードを書いてみました。

とりあえず

int i = 0;
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
    hoge(i);
    i++;
}

で問題なさそうならこれでいいと思います!

両方とりたいアナタに

 以下にコードを貼ります。

 こんな感じ。main関数内はC++11な機能を使ってますが、WithIndexクラス自体はC++03でもコンパイルできます(できるはずです)。range-based forとの相性がよさそうです。普通のforを使う場合は、

typedef WithIndex<std::vector<int> > VectorWithIndex;
VectorWithIndex vi = withIndex(iv);
for(VectorWithIndex::iterator it = vi.begin(); it != vi.end(); ++it)
{
    std::cout << it->index << ": " << it->value << std::endl;
}

 こんな感じで。うーん、autoがないとちょっと使いづらい。いや、かなり使いづらい。

ちょっとした説明

 コード自体はScalaのzipWithIndexを真似てます。こういうシチュエーションってよくあると思うので、ググればきっとたくさんヒットすることでしょう。
 イテレータのindexにループカウンタの値が、valueに実際のイテレータの値が代入されます。range-based forならアロー演算子が使われないのでシンプルなコードになるんですが、C++11より前のC++ではイテレータに入っている値を取り出す際にアロー演算子を使うことが多いかと思います。アロー演算子はポインタを返さなければならないため、一度Elementクラスを変数として書き出しています。ちょっとかっこ悪いしなんだかパフォーマンス落ちてそう。
 range-based forがとても便利です。beginとendがそれぞれ先頭のイテレータ、末尾のイテレータを返す実装になっていれば利用可能です。autoも使えば反復処理がこんなに簡単に!

0 件のコメント :

コメントを投稿