インターフェース版 boost::function
boost::function は静的に型が決まっていないと渡すことが出来なくて、それが不便なことがあったりするので、インターフェースを介して boost::function を呼べる virtual_function というのを作ってみた。
#include <boost/bind.hpp> #include <boost/function.hpp> #include <boost/any.hpp> #include <boost/type_traits.hpp> #include <boost/assert.hpp> #include <boost/none.hpp> #include <boost/shared_ptr.hpp> #include <vector> struct parameters { private: std::vector<boost::any> anys; public: parameters() { } template<int TLength> parameters(boost::any (&anys_)[TLength]) : anys(anys_, anys_ + TLength) { } boost::any& operator[](std::size_t index) { assert(index < length()); return anys[index]; } std::size_t length() const { return anys.size(); } }; parameters make_parameters() { return parameters(); } template<class T0> parameters make_parameters(T0 t0) { boost::any anys[] = { t0 }; return parameters(anys); } template<class T0, class T1> parameters make_parameters(T0 t0, T1 t1) { boost::any anys[] = { t0, t1 }; return parameters(anys); } template<class T0, class T1, class T2> parameters make_parameters(T0 t0, T1 t1, T2 t2) { boost::any anys[] = { t0, t1, t2 }; return parameters(anys); } template<class T0, class T1, class T2, class T3> parameters make_parameters(T0 t0, T1 t1, T2 t2, T3 t3) { boost::any anys[] = { t0, t1, t2, t3 }; return parameters(anys); } template<class T0, class T1, class T2, class T3, class T4> parameters make_parameters(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4) { boost::any anys[] = { t0, t1, t2, t3, t4 }; return parameters(anys); } template<class T0, class T1, class T2, class T3, class T4, class T5> parameters make_parameters(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { boost::any anys[] = { t0, t1, t2, t3, t4, t5 }; return parameters(anys); } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6> parameters make_parameters(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { boost::any anys[] = { t0, t1, t2, t3, t4, t5, t6 }; return parameters(anys); } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7> parameters make_parameters(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { boost::any anys[] = { t0, t1, t2, t3, t4, t5, t6, t7 }; return parameters(anys); } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> parameters make_parameters(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { boost::any anys[] = { t0, t1, t2, t3, t4, t5, t6, t7, t8 }; return parameters(anys); } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9> parameters make_parameters(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { boost::any anys[] = { t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 }; return parameters(anys); } struct null_type { }; template< class R, class T0 = null_type, class T1 = null_type, class T2 = null_type, class T3 = null_type, class T4 = null_type, class T5 = null_type, class T6 = null_type, class T7 = null_type, class T8 = null_type, class T9 = null_type> struct function_traits_base { typedef R result_type; template<int I> struct get { typedef null_type type; }; template<> struct get<0> { typedef T0 type; }; template<> struct get<1> { typedef T1 type; }; template<> struct get<2> { typedef T2 type; }; template<> struct get<3> { typedef T3 type; }; template<> struct get<4> { typedef T4 type; }; template<> struct get<5> { typedef T5 type; }; template<> struct get<6> { typedef T6 type; }; template<> struct get<7> { typedef T7 type; }; template<> struct get<8> { typedef T8 type; }; template<> struct get<9> { typedef T9 type; }; template<int N, class> struct length_helper { static const int value = 1 + length_helper<N + 1, typename get<N + 1>::type>::value; }; template<int N> struct length_helper<N, null_type> { static const int value = 0; }; static const int length = length_helper<0, typename get<0>::type>::value; }; template<class TFunction> struct function_traits; template<class R> struct function_traits<R (void)> : function_traits_base<R> { }; template<class R, class T0> struct function_traits<R (T0)> : function_traits_base<R, T0> { }; template<class R, class T0, class T1> struct function_traits<R (T0, T1)> : function_traits_base<R, T0, T1> { }; template<class R, class T0, class T1, class T2> struct function_traits<R (T0, T1, T2)> : function_traits_base<R, T0, T1, T2> { }; template<class R, class T0, class T1, class T2, class T3> struct function_traits<R (T0, T1, T2, T3)> : function_traits_base<R, T0, T1, T2, T3> { }; template<class R, class T0, class T1, class T2, class T3, class T4> struct function_traits<R (T0, T1, T2, T3, T4)> : function_traits_base<R, T0, T1, T2, T3, T4> { }; template<class R, class T0, class T1, class T2, class T3, class T4, class T5> struct function_traits<R (T0, T1, T2, T3, T4, T5)> : function_traits_base<R, T0, T1, T2, T3, T4, T5> { }; template<class R, class T0, class T1, class T2, class T3, class T4, class T5, class T6> struct function_traits<R (T0, T1, T2, T3, T4, T5, T6)> : function_traits_base<R, T0, T1, T2, T3, T4, T5, T6> { }; template<class R, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7> struct function_traits<R (T0, T1, T2, T3, T4, T5, T6, T7)> : function_traits_base<R, T0, T1, T2, T3, T4, T5, T6, T7> { }; template<class R, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> struct function_traits<R (T0, T1, T2, T3, T4, T5, T6, T7, T8)> : function_traits_base<R, T0, T1, T2, T3, T4, T5, T6, T7, T8> { }; template<class R, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9> struct function_traits<R (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)> : function_traits_base<R, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> { }; class virtual_function_base_impl { public: virtual boost::any Invoke(parameters p) = 0; }; template<class TFunction> class virtual_function_impl : public virtual_function_base_impl { boost::function<TFunction> f_; public: typedef function_traits<TFunction> function_traits; typedef typename function_traits::result_type result_type; private: template<int N> static typename function_traits::get<N>::type get(parameters& p) { return boost::any_cast<typename function_traits::get<N>::type>(p[N]); } template<bool = boost::is_void<result_type>::value> struct Invoker { static result_type Invoke(const boost::function<result_type (void)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(); } template<class T0> static result_type Invoke(const boost::function<result_type (T0)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p)); } template<class T0, class T1> static result_type Invoke(const boost::function<result_type (T0, T1)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p)); } template<class T0, class T1, class T2> static result_type Invoke(const boost::function<result_type (T0, T1, T2)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p), get<2>(p)); } template<class T0, class T1, class T2, class T3> static result_type Invoke(const boost::function<result_type (T0, T1, T2, T3)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p), get<2>(p), get<3>(p)); } template<class T0, class T1, class T2, class T3, class T4> static result_type Invoke(const boost::function<result_type (T0, T1, T2, T3, T4)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p)); } template<class T0, class T1, class T2, class T3, class T4, class T5> static result_type Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p)); } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6> static result_type Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5, T6)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p), get<6>(p)); } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7> static result_type Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5, T6, T7)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p), get<6>(p), get<7>(p)); } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> static result_type Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5, T6, T7, T8)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p), get<6>(p), get<7>(p), get<8>(p)); } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9> static result_type Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)>& f, parameters& p) { assert(p.length() == function_traits::length); return f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p), get<6>(p), get<7>(p), get<8>(p), get<9>(p)); } }; // 戻り値が void である場合の Invoker template<> struct Invoker<true> { static boost::none_t Invoke(const boost::function<result_type ()>& f, parameters& p) { assert(p.length() == function_traits::length); f(); return boost::none; } template<class T0> static boost::none_t Invoke(const boost::function<result_type (T0)>& f, parameters p) { assert(p.length() == function_traits::length); f(get<0>(p)); return boost::none; } template<class T0, class T1> static boost::none_t Invoke(const boost::function<result_type (T0, T1)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p)); return boost::none; } template<class T0, class T1, class T2> static boost::none_t Invoke(const boost::function<result_type (T0, T1, T2)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p), get<2>(p)); return boost::none; } template<class T0, class T1, class T2, class T3> static boost::none_t Invoke(const boost::function<result_type (T0, T1, T2, T3)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p), get<2>(p), get<3>(p)); return boost::none; } template<class T0, class T1, class T2, class T3, class T4> static boost::none_t Invoke(const boost::function<result_type (T0, T1, T2, T3, T4)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p)); return boost::none; } template<class T0, class T1, class T2, class T3, class T4, class T5> static boost::none_t Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p)); return boost::none; } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6> static boost::none_t Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5, T6)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p), get<6>(p)); return boost::none; } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7> static boost::none_t Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5, T6, T7)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p), get<6>(p), get<7>(p)); return boost::none; } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> static boost::none_t Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5, T6, T7, T8)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p), get<6>(p), get<7>(p), get<8>(p)); return boost::none; } template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9> static boost::none_t Invoke(const boost::function<result_type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)>& f, parameters& p) { assert(p.length() == function_traits::length); f(get<0>(p), get<1>(p), get<2>(p), get<3>(p), get<4>(p), get<5>(p), get<6>(p), get<7>(p), get<8>(p), get<9>(p)); return boost::none; } }; public: virtual_function_impl(const boost::function<TFunction>& f) : f_(f) { } virtual boost::any Invoke(parameters p) { return Invoker<>::Invoke(f_, p); } }; typedef boost::shared_ptr<virtual_function_base_impl> virtual_function; template<class Type> struct identify { typedef Type type; }; template<class TFunction> virtual_function make_function(typename identify<const boost::function<TFunction>&>::type f) { return virtual_function(new virtual_function_impl<TFunction>(f)); }
// テンプレートを使わずに呼び出す boost::any call(virtual_function f, parameters p) { return f->Invoke(p); } void func(int n) { } struct A { int f(int n) { return n; } }; void main() { virtual_function f; f = make_function<void (int)>(func); call(f, make_parameters(10)); // func(10) が呼ばれる A a; f = make_function<int (int)>(boost::bind(&A::f, boost::ref(a), _1)); boost::any any = call(f, make_parameters(10)); // a.f(10) が呼ばれる int result = boost::any_cast<int>(any); // a.f(10) の戻り値 }