インターフェース版 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) の戻り値
}