C++のforeach文(範囲ベースfor)【range-based for, for_each】

C++ではforeach文や拡張for文に相当する機能が利用できます。

範囲ベースfor文

範囲ベースのfor文(range-based for statement)または、範囲ベースのforループ(range-based for loop)は、C++11で新たに取り入れられた言語機能です。for (要素 : コンテナ)という形式で利用します。

std::vector<int> v = {1, 2, 3};
for (int i : v) {
   printf("%d, ", i);
}

int a[] = {1, 2, 3};
for (int i : a) {
   printf("%d, ", i);
}

範囲ベースforは内部的にはイテレータの仕組みが利用されているため、begin, endに対応したコンテナクラスや配列であればそのまま利用できます。

なおbegin, endを独自定義することで、独自のオブジェクトを範囲ベースfor文に対応させることも可能です。詳しくは以下のページが参考になります。

イテレータの簡単な作り方と範囲ベースfor対応

for_each

for_eachはC++標準ライブラリのテンプレート関数です。第一引数と第二引数にコンテナのレンジを指定し、第三引数にラムダ式やファンクタ等の関数オブジェクトを渡します。

std::vector<int> v = {1, 2, 3};
std::for_each(v.begin(), v.end(), [](int i) {
   printf("%d, ", i);
});

int a[] = {1, 2, 3};
std::for_each(std::begin(a), std::end(a), [](int i) {
   printf("%d, ", i);
});

const char* s = "abc";
std::for_each(s, s + strlen(s), [](char c) {
  printf("%c", c);
});

どちらを使うべきか

範囲ベースfor文とfor_each関数のどちらを使うべきかで迷うかと思われますが、基本的には先ほど紹介した範囲ベースのfor文の利用をオススメします。for_each関数は既存のファンクタや関数ポインタをコンテナに適用する用途で利用すると便利です。

for_each関数の利用用途

const char* s = "abc";
std::for_each(s, s + 3, putchar);
struct FunctorA { void operator()(int i) { printf("%d,", i); } };
struct FunctorB { void operator()(int i) { printf("%d|", i); } };

std::vector<int> v = {1, 2, 3};

if (argc == 2)
  std::for_each(v.begin(), v.end(), FunctorA());
else
  std::for_each(v.begin(), v.end(), FunctorB());

このように既にある部品(モジュール)を組み合わせてプログラムを構築していくスタイルで威力を発揮します。

範囲forもラムダ式も便利で好きなのですが、コードのモジュール化や再利用性を意識したプロジェクトでは、自然とfor_each関数やファンクタの利用頻度が高まるように思います。

広告