8.1. Boost Function
λファンクタを変数に格納すると都合のいい場合がある。 しかし、最も単純なλファンクタの型であっても、長く、現実的でない。 そして、一般的にはλファンクタの型の変数を宣言することは実現不可能である。 Boost Function ライブラリ [function] は、例えばλファンクタのような任意の関数オブジェクトのラッパを定義する。 これらのラッパは記述しやすい型となっている。 以下に例を示す。
boost::function<int(int, int)> f = _1 + _2;
boost::function<int&(int&)> g = (_1 += 10);
int i = 1, j = 2;
f(i); // returns 3
g(i); // sets i to = 11;
たとえ、一般的な引数を持っているλファンクタであっても、ラップする関数オブジェクトの返り値と引数の型は、ラッパテンプレート boost::function
のテンプレート引数として明示的に記述されなければならない。 boost::function
で関数オブジェクトをラップすると、実際には仮想関数を使用していないが、仮想関数の処理と同等なパフォーマンスのコストが生じてしまう。 boost::function
中にλファンクタを格納することは危険の原因となりうる。 ある種のλファンクタは、λ式の引数のコピーをとる代わりに、束縛変数への参照を格納しているかもしれない。 STL アルゴリズムの呼出しが完了した直後にλファンクタは破棄されるため、STL アルゴリズムの呼出しで、一時的なλファンクタのオブジェクトが使用されている場合は常に安全である。 しかし、boost::function
の内部にラップされたλファンクタは、さらに生存し続け、無効な参照を持つ可能性を作ってしまう。 以下に、例を示す。
int* sum = new int();
*sum = 0;
boost::function<int&(int)> counter = *sum += _1;
counter(5); // ok, *sum = 5;
delete sum;
counter(3); // error, *sum does not exist anymore
8.2. Boost Bind
Boost Bind [bind] ライブラリは部分的に BLL の機能と重複する。 基本的には、Boost Bind ライブラリ(以降 BB)では、BLL の一部の bind 式を実装しているといえる。 しかし、いくつか意味的に異なる部分もある。
BLL と BB は別々に発展し、異った実装となっている。 そのため、BB の bind 式は BLL の bind 式、他の形のλ式には使用することはできない。 BB において、BLL の bind 式を使用するのにも、同じ制限がある。 しかし、BB ライブラリの名前は、名前空間 boost
に存在するのに対し、BLL の名前は、名前空間 boost::lambda
に存在するため、これらの二つのライブラリは共存できる。
BLL はある程度 C++ 標準に順応なコンパイラが必要であるのに対し、BB ライブラリはよりポータブルなコンパイラで十分であり、より多くのコンパイラで機能する。
以降の二つのサブセクションでは、BB と BLL における bind 式の意味的な相違について説明する。
8.2.1. First argument of bind expression
BB においては、対象の関数である bind 式の第一引数の扱い方は、他の引数の扱い方とは異なる。 この引数に関しては、引数の代入が行なわれないのである。 BLL においては、この点においては第一引数は特別扱いはされない。 以下に例を示す。
template<class F>
int foo(const F& f) {
int x;
..
bind(f, _1)(x);
...
}
int bar(int, int);
nested(bind(bar, 1, _1));
foo
の内部の bind 式は次のようになる。
bind(bind(bar, 1, _1), _1)(x)
BLL においては、これは次のように解釈される。
bar(1, x)(x)
一方、BB においては次のようになる。
bar(1, x)
BLL ではこの機能を実現するため、Section 5.9.1.1 で説明したように、関数 foo
の内部の bind 式は次のように書くことが可能である。
bind(unlambda(f), _1)(x);
BLL では三つのプレースホルダしか定義されていないのに対し、BB ライブラリは九つまでのプレースホルダをサポートしている。 これ以上のプレースホルダを提供しない根拠は、いかなる STL アルゴリズムで受理できる関数オブジェクトの最多の引数の数は二つであることである。 BB ライブラリにおいてプレースホルダの数は簡単に増加させることができる。 BLL でも可能であるが、しかしより多くの労力を必要とする。 現在 BLL は実引数を内部的にλファンクタにそのまま渡しており、タプルにラップしたりはしない。 これは、広く使用されているいくつかのコンパイラが最適化において中間のタプルを取り去ることができないためである。 中間のタプルの生成はパフォーマンスに重大な影響を与えてしまう。 特に、単純な(そして最も一般な)λファンクタの場合には重要である。 そして、より多くのプレースホルダも可能であるが、単純なλファンクタのパフォーマンスに関して妥協しない折衷案を選択した。