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は、この比較関数オブジェクトの結果に基づいて大小関係を判定し、昇順にソートします。
