手を動かしてさくさく理解する
C++11 範囲ベース for ループ 入門
Copyright (C) 2014 by Nobuhide Tsuda

 

※ イラスト提供:かわいいフリー素材集「いらすとや」様

C++11 範囲ベース for ループ

C++11 ではいろんなことがとても便利になった。 その中で、簡単に使えてとっても便利なもののひとつが、本稿で説明する「範囲ベース for ループ(range-based for loop)」だ。

範囲の値を参照

「範囲ベース for ループ(range-based for loop)」の書き方は「for( 変数宣言 : 範囲)」だ。範囲としては、通常配列・コンテナクラスオブジェクトが指定できる。
こう書くと、範囲をループし、各要素を変数に自動的に代入してくれる。

例えば、通常配列の要素を全て表示するコードは以下のように書ける。

    int ar[] = {1, 2, 3, 4, 5, 6, 7};
    for(int x : ar) {
        std::cout << x << "\n";     // 1 2 3・・・7 と順に表示される
    }

上記のコードは、下記のコードと同じ意味だ。すごく楽になったのがお分かりだろうか?

    int ar[] = {1, 2, 3, 4, 5, 6, 7};
    for(int i = 0; i < std::end(ar) - std::begin(ar); ++i) {
        std::cout << ar[i] << "\n";
    }

下記のようにコンテナクラスも範囲指定として使える。

    std::vector<int> v{1, 2, 3, 4, 5, 6, 7};
    for(int x : v) {
        std::cout << x << "\n";
    }

下記のように、添字でループしたり、その次のようにイテレータで回すよりも、上記はとても書きやすく、分かりやすい。

    std::vector<int> v{1, 2, 3, 4, 5, 6, 7};
    for(int i = 0; i < (int)v.size(); ++i) {
        std::cout << ar[i] << "\n";
    }
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7};
    for(auto itr = v.begin(); itr != v.end(); ++itr) {
        std::cout << *itr << "\n";
    }

なお、範囲forループで使用する変数の型は auto で書くと便利だぞ。

    std::vector<int> v{1, 2, 3, 4, 5, 6, 7};
    for(auto x : v) {
        std::cout << x << "\n";
    }

念の為に書いておくと、std::map の場合、要素は キーと値のペア(std::pair)なので、 x.first でキーを、x.second で値を参照できる。

    std::map<std::string, int> mp;       // mp を生成
    mp にキー、値のペアを複数設定;
    for(auto x : mp) {
        std::cout << x.first << " " << x.second << "\n";
    }

範囲の値を書き換え

ここまでの例は、範囲の値を参照するだけだったが、for変数宣言時に & を指定しておくと、参照変数となり、範囲の要素の値を書き換えることが出来る。

    int ar[] = {3, 1, 4, 1, 5, 9};
    for(int &x : ar) {
        if( x == 1 )            // 値が1だったら
            x = 123;           // 123 に書き換える
    }
    // ar[] の内容は {3, 123, 4, 123, 5, 9} に変わっている

上記は、配列の全ての要素を調べ、要素の値が1だったら、値を123に書き換える例だ。

break, continue

普通の for ループと同じで、break文、continue 文も使えるぞ。

    int ar[] = {3, 1, 4, 1, 5, 9};
    for(auto x : ar) {
        if( x == 4 )
            break;           // 4を見つけたらループ終了
    }

もちろん、条件が成立したら途中で return してもOKだぞ。

演習問題:解答例

  1. double 型の {1.1, 1.2, 1.3, 1.4, 1.5} 要素を持つ通常配列を宣言し、範囲for文を使って、その内容を全て表示するコードを書きなさい。
  2. double 型の {1.1, 1.2, 1.3, 1.4, 1.5} 要素を持つ std::vector を宣言し、範囲for文を使って、その内容を全て表示するコードを書きなさい。
  3. double 型の {1.1, 1.2, 1.3, 1.4, 1.5} 要素を持つ std::list を宣言し、範囲for文を使って、その内容を全て表示するコードを書きなさい。

演習問題解答例

 

  演習問題解答例

  1. double 型の {1.1, 1.2, 1.3, 1.4, 1.5} 要素を持つ通常配列を宣言し、範囲for文を使って、その内容を全て表示するコードを書きなさい。
  2.     double ar[] = {1.1, 1.2, 1.3, 1.4, 1.5};
        for(auto x : ar) {
            std::cout << x << "\n";
        }
    
  3. double 型の {1.1, 1.2, 1.3, 1.4, 1.5} 要素を持つ std::vector を宣言し、範囲for文を使って、その内容を全て表示するコードを書きなさい。
  4.     std::vector<double> v{1.1, 1.2, 1.3, 1.4, 1.5};
        for(auto x : v) {
            std::cout << x << "\n";
        }
    
  5. double 型の {1.1, 1.2, 1.3, 1.4, 1.5} 要素を持つ std::list を宣言し、範囲for文を使って、その内容を全て表示するコードを書きなさい。
  6.     std::list<double> lst{1.1, 1.2, 1.3, 1.4, 1.5};
        for(auto x : lst) {
            std::cout << x << "\n";
        }