C++0Xの新機能が搭載されたVisual Studio 2010
Microsoftの開発者向け技術情報サイト「MSDN」では、Visual Studio 2010 β1 がリリースされています。IDEがWPFで作られていたり、.NET Frameworkのバージョンが上がっていたりと、Visual Studio 2010では様々な変更/拡張が施されているようですが、C++屋の筆者としては、Visual C++が部分的にせよC++の新規格(通称C++0X)の新しい機能を積極的に取り入れていることが、とても嬉しく思います。
Visual C++ ver. 10に追加されたC++0Xの新機能のひとつ、「ラムダ式(lambda expression)」を少しばかり触ってみましょう。
関数オブジェクトとは
C++がtemplateをサポートし、それにあわせてSTLに代表されるテンプレート・ライブラリがリリースされたのが、1990年代半ば辺りだったでしょうか。STLはベクタ(可変長配列)や双方向リストなどのデータ構造だけでなく、列挙や検索、あるいはソートなどのアルゴリズムを提供してくれます。
アルゴリズムを提供するライブラリは、拡張性の高さが求められます。例えば、検索であれば条件を満たすか否かを判定する関数、ソートであれば2つの要素の大小を判定する関数を、ユーザーが自由に設定できなくてはなりません。
STLではユーザー定義関数をアルゴリズムに与える方法として「関数オブジェクト」を導入しました。関数オブジェクトとは、平たく言えば、文字通り関数として機能するオブジェクト。オブジェクトx
に対し、operator()
が適用できる、すなわちx()
できるならx
は関数オブジェクトです。
例えば、int配列の中からn
で割り切れる最初の要素を検索する場合について、考えてみましょう。STLのアルゴリズムは、ヘッダ<algorithm>
に定義されているfind_if
を使いましょう。
#include <algoritm> #include <iostream> class can_divide { int n_; public: can_divide(int n) : n_(n) {} // nで割り切れるなら true を返す bool operator()(int x) const { return x % n_ == 0; } }; 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, can_divide(n)); if ( found != ar+10 ) { std::cout << n << " で割り切れる数 " << *found << " が見つかりました。" << std::endl; } }
上記コードでは、class can_divide
が関数オブジェクトです。コンストラクタでn
を指定しておけば、can_divide
のインスタンスf
は、f(x)
が呼ばれるとx
がn
で割り切れるかを判断します。find_if
は、与えられた範囲にある要素を1つずつ関数オブジェクトに適用し、trueとなる位置(イテレータ)を返します。
サンプルをもう1つ。<algoritm>
が提供する関数sort
を用い、要素の絶対値で昇順にソートしてみましょう。
#include <algorithm> #include <iostream> class abs_less { public: bool operator()(int x, int y) const { return ( x > 0 ? x : -x ) < ( y > 0 ? y : -y); } }; int main() { int ar[] = { 9, 7, 5, 3, 1, -2, -4, -6, -8, 0 }; std::sort(ar, ar+10, abs_less()); for ( int i = 0; i < 10; ++i ) { std::cout << ar[i] << " "; } }
この例では、class abs_less
が関数オブジェクトです。abs_less
のoperator()
は引数を2つ(x
、y
)を取り、|x| < |y|
ならばtrueを返します。std::sort
は、この比較関数オブジェクトの結果に基づいて大小関係を判定し、昇順にソートします。