#include <iostream>

int& func()
{
    static int p;
    return p;
}

int first_param() { return func() = 0 ; }

int next_param() { return ++func() ; }

template < std::size_t N > struct do_call_fn ;

template <> struct do_call_fn<0>
{ template < typename FN > static int call( FN fn) { return fn() ; } };

template <> struct do_call_fn<1>
{
    template < typename FN > static int call( FN fn)
    { return fn( first_param() ) ; }
};

template <> struct do_call_fn<2>
{
    template < typename FN > static int call( FN fn)
    { auto a = first_param() ; return fn( a, next_param() ) ; }
};

template <> struct do_call_fn<3>
{
    template < typename FN > static int call( FN fn)
    {
        auto a = first_param() ;
        auto b = next_param() ;
        return fn( a, b, next_param() ) ;
    }
};

template <> struct do_call_fn<4>
{
    template < typename FN > static int call( FN fn)
    {
        auto a = first_param() ;
        auto b = next_param() ;
        auto c = next_param() ;
        return fn( a, b, c, next_param() ) ;
    }
};
template < typename... ARGS > int call_fn( int (&fn)( ARGS... ) )
{ return do_call_fn< sizeof...(ARGS) >::call(fn) ; }

int f() { std::cout << "f()\n" ; return 0 ; }
int g(int) { std::cout << "g(int)\n" ; return 1 ; }
int h(int,int) { std::cout << "h(int,int)\n" ; return 2 ; }
int i(int,int,int) { std::cout << "i(int,int,int)\n" ; return 3 ; }
int j(int,int,int,int) { std::cout << "j(int,int,int,int)\n" ; return 3 ; }

int main()
{
   call_fn(f) ;
   call_fn(g) ;
   call_fn(h) ;
   call_fn(i) ;
   call_fn(j) ;
}
