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;
    // 要素に対する処理
  }  

サンプルコード

記事中で紹介したサンプルコードのファイルです。


スポンサーサイト
 
このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
39位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
4位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

02月 | 2017年03月 | 04月
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 -


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。