// Some metaprogramming boilerplate:

#include <tuple>

template<int...> struct seq {};
template<int Min, int Max, int... s> struct make_seq:make_seq<Min, Max-1, Max-1, s...> {};
template<int Min, int... s> struct make_seq<Min, Min, s...> {
  typedef seq<s...> type;
};
template<int Max, int Min=0>
using MakeSeq = typename make_seq<Min, Max>::type;

// helper to unpack a tuple:
template<typename Func, Func f, typename Tuple, int... s>
void do_call( seq<s...>, Tuple&& tup ) {
  f( std::get<s>(tup)... );
}

// Type of the resulting function pointer:
typedef void(*pvoidary)(void*);

template<typename FuncType, FuncType Func, typename... Args>
std::tuple<pvoidary, std::tuple<Args...>*> make_task( Args&&... args ) {
    typedef std::tuple<Args...> pack;
    pack* pvoid = new pack( std::forward<Args>(args)... );
    return std::make_tuple(
        [](void* pdata)->void {
            pack* ppack = reinterpret_cast<pack*>(pdata);
            do_call<FuncType, Func>( MakeSeq<sizeof...(Args)>(), *ppack );
        },
        pvoid
    );
}
#define MAKE_TASK( FUNC ) make_task< typename std::decay<decltype(FUNC)>::type, FUNC >

#include <iostream>


void test( int x ) {
  std::cout << "X:" << x << "\n";
}
void test2( std::string s ) {
  std::cout << "S:" << s.c_str() << "\n";
}
int main() {
  auto task = MAKE_TASK(test)( 7 );
  pvoidary pFunc;
  void* pVoid;
  std::tie(pFunc, pVoid) = task;
  pFunc(pVoid);
  delete std::get<1>(task); // cleanup of the "void*"
  auto task2 = MAKE_TASK(test2)("hello");
  std::tie(pFunc, pVoid) = task2;
  pFunc(pVoid);
  delete std::get<1>(task2); // cleanup of the "void*"
}
