無性にC++でlambda式を使ったコードの書き方を知りたくなって、ちょっと調べて書いてみた。
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v(10);
int n = 0;
std::generate(v.begin(), v.end(), [&n]()->int{return n++;});
std::for_each(v.begin(), v.end(), [](int a){std::cout << a << std::endl;});
return 0;
}
これは大したコードではなくて、10要素のvector<int>型の配列に0から順にインクリメントした値をセットして、配列の中身をすべて表示するだけのもの。lambda式をgenerateとfor_eachの引数の2か所で使っている。
[&n]()->int{return n++;}
1つ目のこれは、main関数内で宣言したint型の変数n(=0)を返しつつ、呼び出すごとにnをインクリメントするので、呼び出すたびに0, 1, 2, … とインクリメントされた値が返ってくるlambda式(無名関数)。
[&n]のところを[n]にすると、値渡しになって変数nの実体は変更されないので、ずっとゼロが返ってくる。と思ったら、VC++2010だとエラーが出てコンパイルできなかった。
C:\work\test>cl lambda1.cpp /EHsc
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
lambda1.cpp
lambda1.cpp(10) : error C3491: 'n': a by-value capture cannot be modified in a non-mutable lambda
この部分のコードをfor文で書くとこんな感じになるはず。
//std::generate(v.begin(), v.end(), [&n]()->int{return n++;});
for (int i = 0; i < v.size(); i++) {
v[i] = n++;
}
[](int a){std::cout << a << std::endl;}
2つめは引数を取るタイプのlambda式。整数を受け取って、iostreamのcoutに流し込んで改行するだけ。
これもfor文で書くとこんな感じになるはず。
//std::for_each(v.begin(), v.end(), [](int a){std::cout << a << std::endl;});
for (int i = 0; i < v.size(); i++) {
std::cout << a << std::endl;
}
[]と()の違いというか意味を真面目に調べてなかったので全く理解できてなかったけど、書いてみると思ったより簡単だった。
ここで書いたコードだとfor文でイテレータを回す方がコードとしては見やすいようにも思うけど、複雑なコンテナでソートなどの処理するような場合は、lambda式で比較条件式を書いた方がすっきりしそうなので、STLをバリバリ使ってコードを書く場合は役に立ちそう。
参考までに実行結果
C:\work\test>cl lambda1.cpp /EHsc
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
lambda1.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:lambda1.exe
lambda1.obj
C:\work\test>lambda1
0
1
2
3
4
5
6
7
8
9