原文:http://www.boost.org/libs/function/doc/tutorial.html
Boost.Function には 2 種類の文法がある。推奨文法と互換文法である。推奨文法は C++ にフィットし、考慮するテンプレートパラメータの数も減り、可読性を高める事が多い。しかし、コンパイラのバグのせいで、推奨文法が使えないコンパイラも有る。互換文法は Boost.Function がサポートする全てのコンパイラで使える。どちらの文法を使うかは、下の表を見て決めて欲しい。
推奨文法 | 互換文法 |
---|---|
|
|
あなたのコンパイラが表に無ければ、推奨文法を試してみて、結果を Boost MLに報告して欲しい。この表を最新に保つためだ。
関数オブジェクトのラッパを定義するには、 function
クラステンプレートをインスタンス化するだけだ。テンプレート引数には、戻り値型と引数型を関数型形式で指定する。ある実装定義の最大値 (デフォルトは 10) までなら、引数は何個でも構わない。以下に、 2 つの int
型のパラメータを取り、float
型を返す関数オブジェクトのラッパ f
の定義を示す。
推奨文法 | 互換文法 |
---|---|
boost::function<float (int x, int y)> f; |
boost::function2<float, int, int> f; |
デフォルトでは、関数オブジェクトのラッパは空である。 f
に代入する関数オブジェクトを作ろう。
struct int_div { float operator()(int x, int y) const { return ((float)x)/y; }; }; f = int_div();
これで、関数オブジェクト int_div
を呼び出す代わりに f
を使える。
std::cout << f(5, 3) << std::endl;
f
には、互換性があれば、どんな関数オブジェクトでも代入できる。 int_div
が 2 つの long
型の引数をとると宣言されていれば、自動的に暗黙の型変換が適用される。引数型に対する唯一の制限は、コピーコンストラクト可能な事である。だから、参照や配列さえ使える。
推奨文法 | 互換文法 |
---|---|
boost::function<void (int values[], int n, int& sum, float& avg)> sum_avg; |
boost::function4<void, int[], int, int&, float> sum_avg; |
void do_sum_avg(int values[], int n, int& sum, float& avg) { sum = 0; for (int i = 0; i < n; i++) sum += values[i]; avg = (float)sum / n; } sum_avg = &do_sum_avg;
関数オブジェクトを格納していないラッパを呼び出すのは事前条件違反である。ヌルの関数ポインタを呼び出そうとするようなものだ。関数オブジェクトのラッパが空かどうかは empty()
メソッドでチェックできる。もっと簡潔なのは、 bool 型の文脈でラッパを使う方法だ。ラッパは、空でなければ true と評価される。例えば、
if (f) std::cout << f(5, 3) << std::endl; else std::cout << "f has no target, so it is unsafe to call" << std::endl;
ラッパを空にするには、 clear()
メンバ関数を使う。
非メンバ関数へのポインタは、 const な関数呼出し演算子を持つ (インスタンスが1つだけ存在する) 関数オブジェクトの一種とみなせる。よって、関数オブジェクトのラッパに直接代入できる。
float mul_ints(int x, int y) { return ((float)x) * y; } f = &mul_ints;
Microsoft Visual C++ version 6 を使う場合を除けば、本当は &
は不要だ。
多くのシステムで、コールバックは特定のオブジェクトのメンバ関数を呼び出す事が多い。これは「引数の束縛」と呼ばれ、 Boost.Function の守備範囲外である。しかし、 Boost.Function には直接メンバ関数を扱う方法が有る。以下のコードのように使う。
推奨文法 | 互換文法 |
---|---|
struct X { int foo(int); }; boost::function<int (X*, int)> f; f = &X::foo; X x; f(&x, 5); |
struct X { int foo(int); }; boost::function2<int, X*, int> f; f = &X::foo; X x; f(&x, 5); |
引数の束縛をサポートするライブラリはいくつか有る。その内 3 つを以下に要約する。
std::bind1st
と std::mem_fun
を一緒に使って、メンバ関数ポインタと (その対象となる) オブジェクトを束縛したものは、 Boost.Function で使える。
推奨文法 | 互換文法 |
---|---|
struct X { int foo(int); }; boost::function<int (int)> f; X x; f = std::bind1st(std::mem_fun(&X::foo), &x); f(5); // Call x.foo(5) |
struct X { int foo(int); }; boost::function1<int, int> f; X x; f = std::bind1st(std::mem_fun(&X::foo), &x); f(5); // Call x.foo(5) |
Boost.Function による関数オブジェクトのコピーが高価 (または不正) な場合が有る。そんな場合は、 Boost.Function に実際の関数オブジェクトの「参照」を格納させる事ができる。ref
や cref
を使う事で、関数オブジェクトの参照のラッパを作成できる。
推奨文法 | 互換文法 |
---|---|
stateful_type a_function_object; boost::function<int (int)> f; f = ref(a_function_object); boost::function<int (int)> f2(f); |
stateful_type a_function_object; boost::function1<int, int> f; f = ref(a_function_object); boost::function1<int, int> f2(f); |
f
も f2
も
a_function_object
のコピーを作成しない。さらに、関数オブジェクトの参照を使えば、 Boost.Function は代入、構築時に例外を起こさない。
Japanese Translation Copyright © 2003 Hiroshi Ichikawa
オリジナルの、及びこの著作権表示が全ての複製の中に現れる限り、この文書の複製、利用、変更、販売そして配布を認める。このドキュメントは「あるがまま」に提供されており、いかなる明示的、暗黙的保証も行わない。また、いかなる目的に対しても、その利用が適していることを関知しない。