原文:http://www.boost.org/libs/function/index.html

C++ BoostHeader <boost/function.hpp>

ヘッダファイル <boost/function.hpp> に含まれるのは、関数オブジェクトのラッパとなるクラステンプレート群である。 Boost.Function の概念はコールバックを一般化したものだ。 Boost.Function は以下の点で関数ポインタと共通の特徴をもっている。 1 つは、何らかの実装によって呼び出される「呼び出しのインタフェース」 (例: 2 つの int 型引数を取り、 float を返す関数) を定義している事。もう 1 つは、呼び出される実装をプログラム実行中に変更できる事だ。

一般に、遅延呼び出しやコールバックを実現するために関数ポインタを使うあらゆる場面で、代わりに Boost.Function を使用できる。そして、それによって呼ばれる側の実装はぐっと自由になる。呼ばれる側にはあらゆる「互換性のある」関数オブジェクト (や関数ポインタ) が指定できる。「互換性がある」とは、 Boost.Function に渡した引数が、対象となる関数オブジェクトの引数に変換できるという事だ[訳注1]

Compatibility Note

Boost.Function は、インタフェースを小さく、分かりやすくするために、一部が再設計された。昔の Boost.Function に有った、いくつかのめったに (または決して) 使われない機能は推奨されなくなり、近々削除される。以下に推奨されなくなった機能とその理由、それに伴うコードの修正法をリストアップする。

新しい文法に移行し、推奨されない機能を削除するためには、 BOOST_FUNCTION_NO_DEPRECATED プリプロセサマクロを定義する。このマクロを定義すると、推奨されない全ての機能が使えなくなる。 BOOST_FUNCTION_NO_DEPRECATED を使ってコンパイルされたプログラムなら、推奨されない機能が削除されても大丈夫だ。

Boost.Function vs. Function Pointers

Boost.Function には関数ポインタに比べていくつかの利点がある。

そしてもちろん、関数ポインタにも Boost.Function に比べていくつかの利点がある。

以上 2 つのリストは Darin Adler のコメントを編集したものである。

Performance

Function object wrapper size

関数オブジェクトのラッパのサイズは 2 つの関数ポインタと、 1 つの関数ポインタまたはデータのポインタ (の大きい方) のサイズになる。一般的な 32 ビットプラットフォームでは、 1 つのラッパ当たり 12 バイトになる。さらに、対象となる関数オブジェクトがヒープに割り当てられる。

Copying efficiency

関数オブジェクトのラッパのコピーによって、格納された関数オブジェクトのコピーのためにメモリ割り当てが発生する。デフォルトのアロケータを、もっと早いカスタムアロケータで置換する事もできる。また、関数オブジェクトのラッパが、対象となる関数オブジェクトの「参照」を格納するように指定できる (refを使用) 。これは関数オブジェクトのコピーが酷く高価な場合に有効だ。

Invocation efficiency

適切なインライン化を行うコンパイラならば、関数オブジェクトの呼び出しによって、関数ポインタを通した呼び出しが 1 回行われる。非メンバ関数ポインタの呼び出しならば、その関数ポインタの呼び出しに加えて、もう 1 回の呼び出しが行われる (コンパイラがとても強力な関数をまたいだ分析を行うならば別だが) 。

Portability

Boost.Function は、できるだけ移植性を高めるように、できるだけ多くのコンパイラ (C++ 標準準拠度が低いものも含む) をサポートするように設計されている。以下のコンパイラは boost::functionに含まれる全てのテストケースに合格した。

以下のコンパイラでも boost::functionを使えるが、いくつか問題がある。

あなたのコンパイラが上のリストに無ければ、 boost::function ライブラリを使えるかチェックするための小さなテスト群があるので、これを使える。標準に準拠したコンパイラなら、修正無しでコードをコンパイルできるはずだが、問題が起きたらバグレポートを送って欲しい。

Design rationale

Combatting virtual function bloat

多くのコンパイラでは、仮想関数の使用によって「コードの膨張」が起きがちである。クラスが仮想関数を持つ場合、オブジェクトの型を分類する補助関数を作る必要が有る。私達の経験では、多くの boost::function オブジェクトが使われると、この補助関数が実行可能ファイルのサイズを大きく膨張させる。

Boost.Function では、仮想関数の代わりに非メンバ関数を使った、代わりの等価なアプローチをとっている。 Boost.Function オブジェクトが関数オブジェクトを呼び出すためには、本質的に 2 つのポインタを持つ必要がある。所有する関数オブジェクトへの void ポインタと、関数オブジェクトの「呼び出し役」への void ポインタ (関数ポインタが代入される) だ。 Boost.Function が提供する、引数と戻り値の変換は、この呼び出し役が実行する。第 3 のポインタは「管理者」と呼ばれる非メンバ関数を指す。これは関数オブジェクトのコピーと破棄を扱う。この方法はタイプセーフだ。なぜなら、関数オブジェクトを実際に扱う関数である呼び出し役と管理者は、関数オブジェクトの型を知らされてインスタンス化されるので、入ってくる void ポインタ (関数オブジェクトへのポインタ) を、正しい型に安全にキャストできるからだ。

Acknowledgements

たくさんの人がこのライブラリの作成に参加した。 William Kempf 、 Jesse Jones 、 Karl Nelson は、ライブラリのインタフェースと守備範囲を、他のライブラリとは独立したものにする上で大きな助けになってくれた。 John Maddock は公式なレビューをやってくれた。他にもたくさんの人がレビューをして、インタフェース、実装、ドキュメントについて優れたコメントを寄せてくれた。


[訳注1] 戻り値にも互換性が必要。
[訳注2] この機能 (呼び出しポリシー) は推奨されておらず、将来削除される。


Doug Gregor

Japanese Translation Copyright © 2003 Hiroshi Ichikawa
オリジナルの、及びこの著作権表示が全ての複製の中に現れる限り、この文書の複製、利用、変更、販売そして配布を認める。このドキュメントは「あるがまま」に提供されており、いかなる明示的、暗黙的保証も行わない。また、いかなる目的に対しても、その利用が適していることを関知しない。