第3回ではラムダ式を説明します。 

ラムダ式は簡単に説明すると、従来の関数オブジェクトの代わりになる機能です。
前回の講座のように<algorithm>の機能では、関数オブジェクトを利用する事が多くあります。

 1: #include <iostream>
 2: #include <vector>
 3: #include <algorithm>
 4:
 5: using namespace std;
 6:
 7: struct CPrint
 8: {
 9:	void operator()(int value)
10:	{
11:		cout << value << endl;
12:	}
13: };
14:
15: int main()
16: {
17:	vector<int> vec;
18:
19:	int i = 0;
20:	while (i < 10)
21:	{
22:		vec.push_back(i * i);//iの2乗の値を入れる(0,1,4,9,...,81)
23:		i++;
24:	}
25:
26:	for_each(vec.begin(), vec.end(), CPrint());
27:
28:	return 0;
29: }

7行目からのCPrintの部分がそうです。これを表示以外の機能も複数作る必要があるとなったとき、無駄に行数が増えて可読性が下がりやすいです。
そこで、ラムダ式という機能がC++11で登場しました。書き方は

[キャプチャ](引数)->戻り値の型{文}

となります。従来のC++ではあまり見慣れない書き方なので戸惑うかと思いますが覚えてしまえば簡単です。
試しに上記のプログラムにラムダ式を使用してみます。

 1: #include <iostream>
 2: #include <vector>
 3: #include <algorithm>
 4:
 5: using namespace std;
 6:
 7: int main()
 8: {
 9:	vector<int> vec;
10:
11:	int i = 0;
12:	while (i < 10)
13:	{
14:		vec.push_back(i * i);//iの2乗の値を入れる(0,1,4,9,...,81)
15:		i++;
16:	}
17:
18:	for_each(vec.begin(), vec.end(), [](int n)->void{cout << n << endl;});
19:
20:	return 0;
21: }

18行目のfor_eachの第3引数にラムダ式が使われています。
先ほどのラムダ式の書き方と比較すれば分かりますが、
・引数にint型のnを1つ
・戻り値はvoid(つまり無し)
・処理はcoutでnの値を出力
となり、CPrintと同じだということが分かります。
こうすることにより関数オブジェクトを外部に書く必要がなくなるためスマートに書くことが出来るようになります。
次に外部参照を使う場合などの例としてもう少し加筆したバージョンを書きます。

 1: #include <iostream>
 2: #include <vector>
 3: #include <algorithm>
 4:
 5: using namespace std;
 6:
 7: int main()
 8: {
 9:	vector<int> vec(10);
10:
11:	//配列を乱数で初期化
12:	generate(vec.begin(), vec.end(), []()->int{return rand();});
13:
14:	//配列の中身を表示
15:	for_each(vec.begin(), vec.end(), [](int n)->void{cout << n << endl;});
16:
17:	//配列の合計を求める
18:	int sum = 0;
19:	for_each(vec.begin(), vec.end(), [&sum](int n)->void{sum += n;});
20:
21:	cout << sum << endl;
22:
23:	return 0;
24: }

※12行目のgenerate関数は配列を第3引数の関数オブジェクトの方法で初期化するだけです。
注目して欲しいのは19行目なのですが、

[&sum](int n)->void{sum += n;}

と[]内に&sumと書かれているのが分かります。つまりこれは、
・外部変数であるsumを参照してラムダ式で使用
ということになります。今回の場合参照なので、ラムダ式内でsumの値を書き換えればそれが反映されます。
このキャプチャの書き方は以下のようになります。

[]     キャプチャなし
[x]    xを値渡し
[&x]   xを参照渡し
[x,&y] xを値渡し、yを参照渡し
[=]    同スコープ内の外部変数を値渡し
[&]    同スコープ内の外部変数を参照渡し
[&,x]  xを値渡し、それ以外の同スコープ内の外部変数を参照渡し

最後にラムダ式の他の使い方を軽く紹介します。

 1: #include <iostream>
 2: #include <functional>
 3:
 4: using namespace std;
 5:
 6: void loopPrint(function<void(void)> func, int cnt)
 7: {
 8:	for (int i = 0; i < cnt; i++)
 9:	{
10:		func();
11:	}
12: }
13:
14: int main()
15: {
16:	//変数のように扱うことも出来る
17:	auto m = []()->void{cout << "Hello World!" << endl;};
18:
19:	//引数として渡す事も可能
20:	loopPrint(m, 5);
21:
22:	return 0;
23: }

※loopPrintの引数のfunctionは引数、戻り値無しの関数オブジェクトを受け取るものだと思ってください。
第1回で書いたautoと組み合わせて変数のように扱うことも出来ます。同様に引数に渡すことも出来ます。
このようにラムダ式を上手く使うことで今まで別の所に書いていた関数オブジェクトを無くすことが出来るので、頑張って覚えましょう。

以上でラムダ式の説明を終わります。

前→C++11講座2回
次→C++11講座4回

選択肢 投票
卍解〜 3  
あっ、おい待てぃ 0  
(C++は)ぬぅぅわぁぁぁん疲れたもぉぉぉん 0  

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-12-01 (金) 00:20:28