function_allows_small_object_optimization
というメタ関数が boost/function/function_base.hpp に定義されています。
これが何かというと名前の通りで、このメタ関数が true を返す場合には、boost::function に渡す関数オブジェクトが十分に小さい(かつ正しい場所にオブジェクトが配置できる)のでメモリを動的に確保せずに boost::function を構築できるということを表します。
つまり、
void func(int) { } boost::function<void (int)> f(boost::bind(func, 10));
これぐらいの小さい関数オブジェクトならメモリを動的に確保しません。
これが組み込み系やってる自分にはすごく便利で、これのおかげでどんどん boost::function が使えます。
また、絶対に動的に確保されたくない!という場合は、
template<class T, class F> boost::function<T> make_small_function(F f, typename boost::enable_if< boost::detail::function::function_allows_small_object_optimization<F> >::type* = 0) { return f; }
こんなのを作っておけば、大きい関数オブジェクトを渡した際にコンパイルエラーになります(もちろん detail 内のを使ってるので非公式)。
struct hoge1 { int a, b, c, d, e; }; struct hoge2 { int a, b, c, d, e, f; }; void func1(hoge1) { } void func2(hoge2) { } // boost 1.38 & VS2008 で実験 int main() { using namespace boost; // OK: このサイズならなんとかいけた function<void ()> f1(make_small_function<void ()>(bind(func1, hoge1()))); // エラー: このサイズは無理だった function<void ()> f2(make_small_function<void ()>(bind(func2, hoge2()))); }
関数テンプレートの型を書くのが面倒だという場合は適当に operator T() か何かを使ってやるとか、そもそもこの例なら make_small_function は function を構築して返さずに F をそのまま返すだけでいいという話も。
で、どうしても f2 を動的にメモリを確保せずに構築したい!という場合には、「関数オブジェクトが十分に小さいかどうか」の閾を下げてやります。これは boost/function/function_base.hpp にある union function_buffer の中で
union function_buffer { char dummy[32]; ... };
こんなのを追加すれば、きっと大きい関数オブジェクトでもメモリを確保しなくなるのですが、その代わりに全体の function に対するコピーのコストが増えてしまいます。
しかも boost 本体に手を入れることになるのでよく考えてからやる必要がありそうです。