[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 件のコメント :
コメントを投稿