c++boost.gif (8819 bytes)HomeLibrariesPeopleFAQMore

Tutorial

Boost.Function には 2 種類の文法がある。推奨文法と互換文法である。推奨文法は C++ にフィットし、考慮するテンプレートパラメータの数も減り、可読性を高める事が多い。しかし、コンパイラのバグのせいで、推奨文法が使えないコンパイラも有る。互換文法は Boost.Function がサポートする全てのコンパイラで使える。どちらの文法を使うかは、下の表を見て決めて欲しい。

推奨文法互換文法
  • GNU C++ 2.95.x, 3.0.x, 3.1.x
  • Comeau C++ 4.2.45.2
  • SGI MIPSpro 7.3.0
  • Intel C++ 5.0, 6.0
  • Compaq's cxx 6.2
  • 推奨文法をサポートする全てのコンパイラ
  • Microsoft Visual C++ 6.0, 7.0
  • Borland C++ 5.5.1
  • Sun WorkShop 6 update 2 C++ 5.3
  • Metrowerks CodeWarrior 8.1

あなたのコンパイラが表に無ければ、推奨文法を試してみて、結果を Boost MLに報告して欲しい。この表を最新に保つためだ。

Basic Usage

関数オブジェクトのラッパを定義するには、 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;

関数オブジェクトを格納していないラッパを呼び出すのは事前条件違反である。ヌルの関数ポインタを呼び出そうとするようなものだ。この場合、 bad_function_call 例外が発生する。関数オブジェクトのラッパが空かどうかは、 bool 型の文脈で使う (ラッパが空でなければ true と評価される) か 0 と比較する事でチェックできる。例えば、

if (f)
  std::cout << f(5, 3) << std::endl;
else
  std::cout << "f has no target, so it is unsafe to call" << std::endl;

また、 empty() メソッドはラッパが空かどうかを返す。

最後に、ラッパを空にするには 0 を代入するか、 clear() メンバ関数を呼べばいい。 e.g.,

f = 0;

Free functions

非メンバ関数へのポインタは、 const な関数呼出し演算子を持つ (インスタンスが1つだけ存在する) 関数オブジェクトとみなせる。よって、関数オブジェクトのラッパに直接代入できる。

float mul_ints(int x, int y) { return ((float)x) * y; }

f = &mul_ints;

Microsoft Visual C++ version 6 を使う場合を除けば、本当は & は不要だ。

Member functions

多くのシステムで、コールバックは特定のオブジェクトのメンバ関数を呼び出す事が多い。これは「引数の束縛」と呼ばれ、 Boost.Function の守備範囲外である。しかし、 Boost.Function には直接メンバ関数を扱う方法が有る。以下のコードのように使う。

struct X {
  int foo(int);
};

推奨文法互換文法
boost::function<int (X*, int)> f;

f = &X::foo;
  
X x;
f(&x, 5);
boost::function2<int, X*, int> f;

f = &X::foo;
  
X x;
f(&x, 5);

引数の束縛をサポートするライブラリはいくつか有る。その内 3 つを以下に要約する。

  • Bind 。このライブラリを使えば、あらゆる関数オブジェクトの引数を束縛できる。軽くて移植性が高い。

  • C++ 標準ライブラリ。 std::bind1ststd::mem_fun を一緒に使って、メンバ関数ポインタと (その対象となる) オブジェクトを束縛したものは、 Boost.Function で使える。

    推奨文法互換文法
      boost::function<int (int)> f;
      X x;
      f = std::bind1st(
            std::mem_fun(&X::foo), &x);
      f(5); // Call x.foo(5)
      boost::function1<int, int> f;
      X x;
      f = std::bind1st(
            std::mem_fun(&X::foo), &x);
      f(5); // Call x.foo(5)

  • Lambda ライブラリ。このライブラリは、自然な C++ の文法を使って関数オブジェクトを構築する強力な機構を提供する。 Lambda は、コンパイラが C++ 標準にかなり準拠していないと使えない。

References to Functions

Boost.Function による関数オブジェクトのコピーが高価 (または不正) な場合が有る。そんな場合は、 Boost.Function に実際の関数オブジェクトの「参照」を格納させる事ができる。refcref を使う事で、関数オブジェクトの参照のラッパを作成できる。

推奨文法互換文法
  stateful_type a_function_object;
  boost::function<int (int)> f;
  f = boost::ref(a_function_object);

  boost::function<int (int)> f2(f);
  stateful_type a_function_object;
  boost::function1<int, int> f;
  f = boost::ref(a_function_object);

  boost::function1<int, int> f2(f);

こうすれば、 fa_function_object のコピーを作成しない。 f が持つ a_function_object の参照が f2 の対象となった時も、 a_function_object のコピーは作成されない。さらに、関数オブジェクトの参照を使えば、 Boost.Function は代入、構築時に例外を起こさない。

Last revised: February 18, 2003 at 03:32:15 GMTCopyright ゥ 2001-2003 Douglas Gregor