もっと手軽に書けないのか!? …ラムダ式
関数オブジェクトを定義し、そのインスタンスをアルゴリズムの引数に与えることで、ユーザー(プログラマ)の期待する解を得ているわけですが、上記サンプルで定義した関数オブジェクトのキモとなっているのはそれぞれ、
{ return x % n_ == 0; }
{ return ( x > 0 ? x : -x ) < ( y > 0 ? y : -y);}
わずかにこの部分だけです。たったこれだけのためにcan_divideやらabs_lessやら、classを定義しなければなりません。このわずらわしさを一気に解消してくれるのが、C++0Xで導入されるラムダ式(lambda expression)です。先ほどのサンプルをラムダ式で表現すると、それぞれ次のようになります。
/*
* n で割り切れる要素を探す
*/
#include <algorithm>
#include <iostream>
int main() {
int ar[] = { 9, 7, 5, 3, 1, -2, -4, -6, -8, 0 };
int n = 4;
int* found = std::find_if(ar, ar+10,
// ↓これがラムダ式
[n](int x) { return x % n == 0;} );
if ( found != ar+10 ) {
std::cout << n << " で割り切れる数 "
<< *found << " が見つかりました。" << std::endl;
}
}
/*
* 絶対値で昇順にソートする
*/
#include <algorithm>
#include <iostream>
int main() {
int ar[] = { 9, 7, 5, 3, 1, -2, -4, -6, -8, 0 };
std::sort(ar, ar+10,
// ↓これがラムダ式
[](int x, int y) { return ( x > 0 ? x : -x ) < ( y > 0 ? y : -y); });
std::for_each(ar, ar+10,
// ↓これもラムダ式
[](int x) { std::cout << x << " ";});
}
いかがですか? あきれるほど簡単になりますね。いずれのサンプルでも、関数オブジェクトの()演算子での処理を、そのままfind_ifやsortの引数に書き下しています。従来、わざわざ定義していた関数オブジェクトを直接書き下すことができるのが、ラムダ式の機能です。
ラムダ式の構文
ラムダ式は以下に示す6つの部分で構成されています。

1:lambda-introducer
ラムダ式は[]から定義が始まります。[]の中には、キャプチャ宣言を記述します(後述)。
2:lambda-parameter-declaration-list
ラムダ式に与える引数の並びです。引数のデフォルト値は指定できませんし、可変長パラメータも不可。名前のない引数も許されません。
[](int x = 3) { ... } // error: デフォルト値不可
[](int x, int y , ...) { ... } // error: 可変長パラメータ不可
[](int x, int) { ... } // error: 無名引数不可
3:mutable-specification
ラムダ内にキャプチャ(後述)された変数の書き換え(代入/変更)を許すとき、「mutable」を指定します。
4:exception-specification
ラムダ式の中から例外をthrowするとき、「throw(送出される例外の並び)」を記述します。
5:lambda-return-type-clause
ラムダ式が返す値の型を->の後ろに指定します。ラムダ式の本体が1つのreturn式であるとき、またはラムダ式が値を返さないときは省略可能です。
[](int x) { std::cout << x; } // 省略可: void とみなす
[](int x) { return x*2; } // 省略可: intとみなす
6:compound-statement
ラムダ式の最後にあるのが、ラムダ式で評価される本体(lambda-body)です。
ラムダ式を変数に
ラムダ式は関数オブジェクトとして機能し、変数に格納できます。このときの変数の型には、C++0Xで新たに導入された型推論:auto、もしくは標準ライブラリが提供するクラス・テンプレート:functionが使えます。
#include <iostream>
#include <string>
#include <functional>
// Visual C++ では TR1ライブラリが std::tr1 に置かれている。
// std::tr1:: を std:: と略記するための便法。
namespace std { using namespace std::tr1; }
int main() {
// autoによる
auto println =
[](const std::string& str) { std::cout << str << std::endl; };
// std::function<>による
std::function<std::string (const std::string&)> polite =
[](const std::string& str) { return str+"さん"; };
std::string msg = polite("香田仁"); // politeの評価(呼び出し)
println(msg); // printlnの評価(呼び出し)
println(polite("いちにの"));
}
