C++11 範囲に基づく for 文
多くのスクリプト言語では for in の形式でコンテナーの要素にアクセスできます。
Boost や Qt などでは C++ でもなんとかそれを実現させようとマクロを駆使して for_each として定義されていました。
しかし、とうとう C++11 で範囲 for は言語機能として正式に追加されました。
今回はそんな 範囲 for について紹介します。
範囲 for とは
範囲 for というのは C++11 でThe range-based for statement(範囲に基づく for 文) として規定されたもので、 配列、リストといったコンテナーの各要素に順にアクセスする for です。
プログラミング中では、配列などのコンテナーに対してループを回して要素にアクセスする というのはよく行う処理です。
その際、 今まではループカウンターを回したり、イテレーターを使っていたと思います。 範囲 for を使えば次のように書けます。
vector<int> ary = { 3,2,9,6 }; for (auto elem : ary) { cout << elem << endl; }ループカウンターやイテレーターを書く必要がなく、簡単に書けるようになります。 すっきりしたので、 "コンテナーの要素にアクセスしている" というコードの意図が分かり易くなるという利点もあります。
また、添え字アクセスと違い、イテレーターのようにランダムアクセス以外にも使える汎用性があります。
なお、この考えを一歩進めると関数型のデータ処理となり、 for の逐次処理以外のいろんな処理ができるようになります。
範囲 for の対象
範囲 for に使えるコンテナーは次の 3 つです。- STL のコンテナーなど begin(), end() メソッドを持つクラス
- 配列
- 初期化リスト
配列:
int cary[] = { 3,2,9,6 }; for (auto elem : cary) { cout << elem << endl; }初期化リスト:
for (auto elem : { 3,2,9,6 }) { cout << elem << endl; }
要素の型
範囲 for の要素(elem)の定義にはコンテナーの要素の型を記述します。 これには C++11 に型変換として追加された auto が使えます。その際、関数の引数のようにコンテナーに変更を加えるかどうかによって、 参照(auto&)か const 参照(const auto &)になります。
変更を加える:
vector<string> strs = { "foo", "bar", "baz" }; for (auto &elem : strs) { elem += "!"; } // { "foo!", "bar!", "baz!" }変更を加えない:
vector<string> strs = { "foo", "bar", "baz" }; for (const auto &elem : strs) { cout << elem << endl; }ただし、最初のサンプルのように要素が int などサイズが小さい場合は、 コピーしても問題がないため、ただの auto にします。
また、参照ではなく、ポインターを指定することも出来ます。
std::map の場合
Boost の for_each の時は std::map だとちょっと面倒でした。 範囲 for の場合は問題なく使えます。map<string, int> strmap = { { "foo", 3 }, { "bar", 2 }, { "baz", 9 } }; for (const auto &elem : strmap) { cout << elem.first << " - " << elem.second << endl; }std::map の場合の要素は std::pair です。
範囲 for の対象は begin(), end() を持つ必要がありました。 すなわち、各要素にはイテレーターを使ってアクセスしています。
前章では要素の型をいくつか紹介しましたが、 「イテレーターから導けるものが型として使える」と言えます。
範囲 for は次の記述を簡略化したものと考えると分かりやすいと思います。
for (auto itr = ary.begin() ; itr != ary.end() ; itr++) { auto elem = *itr; // 要素に対する処理 }
サンプルコード
記事中で紹介したサンプルコードのファイルです。- 関連記事
Facebook コメント
コメント