Boost.Functionの実装の概要

  • コンパイラにとって、「関数(invoke)」の方が「仮想関数を含むクラス(holder)」よりも実装が簡単なのでコードサイズが小さくなる
  • 対象が関数のみであるということを利用して汎用的な解決策である仮想関数の利用を避けることができる


[]#include[][] <iostream>[]
[]#include[][] <memory>[]
[]#include[][] <boost/type_traits.hpp>[]
[]#include[][] <boost/mpl/if.hpp>[]

[]using[] []namespace[] []std[];

[]struct[] []my_function[] {
[]int[] []operator[]()([]double[], []float[]) []const[] { []wcout[] << []L[][]"my_function called"[] << []endl[]; []return[] 1; }


};

[]int[] []your_function[]([]double[], []float[]) { []wcout[] << []L[][]"your_function called"[] << []endl[]; []return[] 1; }

[]namespace[] []pst_function_using_virtual[] {
[]// See: boost/any, boost/spirit/rule_t[]

[]// the function, primary decl.[]
[]template[]< []class[] []Signature[] >
[]class[] []function[];

[]// partial spec.[]
[]template[]< []class[] []R[], []class[] []T0[], []class[] []T1[] >
[]class[] []function[]< []R[] ([]T0[], []T1[]) >
{
[]struct[] []placeholder[]
{
[]virtual[] ~[]placeholder[]() { }
[]virtual[] []R[] []operator[]()([]T0[],[]T1[]) []const[] = 0;
};

[]template[]< []class[] []FunctorType[] >
[]struct[] []holder[] : []placeholder[]
{
[]FunctorType[] []held[];
[]holder[]([]FunctorType[] []const[]& []f[]) : []held[]([]f[]) { }
[]virtual[] []R[] []operator[]()([]T0[] []a0[], []T1[] []a1[]) []const[] { []return[] []held[]([]a0[], []a1[]); }
};

[]public[]:
[]template[]< []class[] []FunctorType[] >
[]function[]([]FunctorType[] []const[]& []f[]) : []content[]([]new[] []holder[]<[]FunctorType[]>([]f[]))
{ }

[]R[] []operator[]()([]T0[] []a0[], []T1[] []a1[]) []const[] { []return[] (*[]content[])([]a0[], []a1[]); }

[]private[]:
[]std[]::[]auto_ptr[]<[]placeholder[]> []content[];
};

[]void[] []test[]() {
[]my_function[] []f_[];
[]function[]<[]int[] ([]double[], []float[])> []f1[]([]f_[]);
[]f1[](3.0, 4.0);
[]function[]<[]int[] ([]double[], []float[])> []f2[](&[]your_function[]);
[]f2[](3.0, 4.0);
}
} []// pst_function_using_virtual[]


[]namespace[] []pst_function[] {
[]// See: boost/function[]

[]namespace[] []bst[] = []boost[];
[]namespace[] []mpl[] = []boost[]::[]mpl[];

[]// tag-dispatching[]
[]struct[] []function_obj_tag[] { };
[]struct[] []function_ptr_tag[] { };

[]template[]< []class[] []F[] >
[]struct[] []get_function_tag[]
: []mpl[]::[]if_[]<[]bst[]::[]is_pointer[]<[]F[]>, []function_ptr_tag[], []function_obj_tag[]>
{ };

[]// any_pointer, the union[]
[]union[] []any_pointer[]
{
[]void[]* []obj_ptr[];
[]void[] (*[]func_ptr[])(); []// 関数ポインタとvoid*間のキャストは許されないので必要[]
};

[]// managers, the manual virtuality[]
[]template[]< []class[] []FunctionObj[], []class[] []R[], []class[] []T0[], []class[] []T1[] >
[]struct[] []function_obj_manager[]
{
[]static[] []R[] []invoke[]([]any_pointer[] []function_obj_ptr[], []T0[] []a0[], []T1[] []a1[])
{
[]FunctionObj[]* []f[] = []reinterpret_cast[]<[]FunctionObj[]*>([]function_obj_ptr[].[]obj_ptr[]);
[]return[] (*[]f[])([]a0[], []a1[]);
}

[]static[] []void[] []destroy[]([]any_pointer[] []function_obj_ptr[])
{
[]FunctionObj[]* []f[] = []reinterpret_cast[]<[]FunctionObj[]*>([]function_obj_ptr[].[]obj_ptr[]);
[]delete[] []f[];
}
};

[]template[]< []class[] []FunctionPtr[], []class[] []R[], []class[] []T0[], []class[] []T1[] >
[]struct[] []function_ptr_manager[]
{
[]static[] []R[] []invoke[]([]any_pointer[] []function_ptr[], []T0[] []a0[], []T1[] []a1[])
{
[]FunctionPtr[] []f[] = []reinterpret_cast[]<[]FunctionPtr[]>([]function_ptr[].[]func_ptr[]);
[]return[] []f[]([]a0[], []a1[]);
}

[]static[] []void[] []destroy[]([]any_pointer[])
{
[]// do nothing[]
}
};

[]// the function, primary decl.[]
[]template[]< []class[] []Signature[] >
[]class[] []function[];

[]// partial spec. for signature-style[]
[]template[]< []class[] []R[], []class[] []T0[], []class[] []T1[] >
[]class[] []function[]< []R[] ([]T0[], []T1[]) >
{
[]public[]:
[]typedef[] []R[] []result_type[];
[]// data members[]
[]result_type[] (*[]invoker[])([]any_pointer[], []T0[], []T1[]);
[]void[] (*[]destroyer[])([]any_pointer[]);
[]any_pointer[] []functor[];

[]// ctor[]
[]template[]< []class[] []FunctorType[] >
[]function[]([]FunctorType[] []f[])
{
[]typedef[] []typename[] []get_function_tag[]<[]FunctorType[]>::[]type[] []tag[];
[]assign_to[]([]f[], []tag[]());
}

[]// for function object[]
[]template[]< []class[] []FunctionObj[] >
[]void[] []assign_to[]([]FunctionObj[] []f[], []function_obj_tag[])
{
[]typedef[] []function_obj_manager[]<[]FunctionObj[], []R[], []T0[], []T1[]> []actual_manager[];
[]invoker[] = &[]actual_manager[]::[]invoke[];
[]destroyer[] = &[]actual_manager[]::[]destroy[];

[]FunctionObj[]* []new_f[] = []new[] []FunctionObj[]([]f[]);
[]functor[].[]obj_ptr[] = []static_cast[]<[]void[]*>([]new_f[]);
}

[]// for function pointer[]
[]template[]< []class[] []FunctionPtr[] >
[]void[] []assign_to[]([]FunctionPtr[] []f[], []function_ptr_tag[])
{
[]typedef[] []function_ptr_manager[]<[]FunctionPtr[], []R[], []T0[], []T1[]> []actual_manager[];
[]invoker[] = &[]actual_manager[]::[]invoke[];
[]destroyer[] = &[]actual_manager[]::[]destroy[];

[]functor[].[]func_ptr[] = []reinterpret_cast[]<[]void[] (*)()>([]f[]);
}

[]// the operator()[]
[]result_type[] []operator[]()([]T0[] []a1[], []T1[] []a2[]) []const[]
{
[]return[] []invoker[]([]functor[], []a1[], []a2[]);
}

[]// dtor[]
~[]function[]()
{
[]destroyer[]([]functor[]);
}
}; []// function[]


[]void[] []test[]() {
[]my_function[] []f_[];
[]function[]<[]int[] ([]double[], []float[])> []f1[]([]f_[]);
[]f1[](3.0, 4.0);
[]function[]<[]int[] ([]double[], []float[])> []f2[](&[]your_function[]);
[]f2[](3.0, 4.0);
}

} []// namespace pst_function[]