#include <utility>
#include <functional>
#include <iostream>

    template<class Is, size_t I>
    struct add;
    template<class Is, size_t I>
    using add_t=typename add<Is,I>::type;

    template<size_t...Is, size_t I>
    struct add<std::index_sequence<Is...>, I>{
      using type=std::index_sequence<(I+Is)...>;
    };

    template<template<class...>class Z, class Is, class...Ts>
    struct partial_apply;
    template<template<class...>class Z, class Is, class...Ts>
    using partial_apply_t=typename partial_apply<Z,Is,Ts...>::type;

    template<template<class...>class Z, size_t...Is, class...Ts>
    struct partial_apply<Z,std::index_sequence<Is...>, Ts...> {
      using tup = std::tuple<Ts...>;
      template<size_t I> using e = std::tuple_element_t<I, tup>;

      using type=Z< e<Is>... >;
    };

    template<template<class...>class Z, class...Ts>
    struct split {
      using left = partial_apply_t<Z, std::make_index_sequence<sizeof...(Ts)/2>, Ts...>;
      using right = partial_apply_t<Z, add_t<
        std::make_index_sequence<(1+sizeof...(Ts))/2>,
        sizeof...(Ts)/2
      >, Ts...>;
    };
    template<template<class...>class Z, class...Ts>
    using right=typename split<Z,Ts...>::right;
    template<template<class...>class Z, class...Ts>
    using left=typename split<Z,Ts...>::left;

    template<class...Sigs>
    struct functions_impl;

    template<class...Sigs>
    using functions = typename functions_impl<Sigs...>::type;

    template<class...Sigs>
    struct functions_impl:
      left<functions, Sigs...>,
      right<functions, Sigs...>
    {
       using type=functions_impl;
       using A = left<functions, Sigs...>;
       using B = right<functions, Sigs...>;
       using A::operator();
       using B::operator();
       template<class F>
       functions_impl(F&& f):
         A(f),
         B(std::forward<F>(f))
       {}
    };
    template<class Sig>
    struct functions_impl<Sig> {
      using type=std::function<Sig>;
    };

int main()
{
	functions<void(int), void(double)> f = [](auto&& x){std::cout << x << '\n';};
	f(3.14);
	f(3);
}