Passing position of variadic template argument

2020-02-28 06:39发布

I would like to create a function that takes a variable number of template arguments. Later with these arguments the function should pass their position like this:

template<typename R, typename Args...>
R myFunction(Data &data, void *function) {
    auto f = (R (*)(Args...))function;
    return f(read<Args1>(data, 1), read<Args2>(data, 2), ...);// <-- This is the problem
}

The given code is of course not compilable. Is there any way to fix it? Is there a way to do it without variadic templates without too much code duplication?

1条回答
混吃等死
2楼-- · 2020-02-28 07:24

Yes, that is possible:

// we need a compile-time helper to generate indices
template< std::size_t... Ns >
struct indices
{
  typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices
{
  typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 >
{
  typedef indices<> type;
};

With these helpers, you need one forwarder for your function like this:

template<typename R, typename... Args, std::size_t... Ns>
R myFunctionImpl(void *Data, void *function, indices<Ns...> ) {
    auto f = (R (*)(Args...))function;
    return f(read<Args>(Data, Ns + 1)...);// +1 because indices is zero-based
}

template<typename R, typename... Args>
R myFunction(void *Data, void *function) {
   return myFunctionImpl< R, Args... >( Data, function, typename make_indices<sizeof...(Args)>::type() );
}

EDIT: How does it work? First, we determine the size of the argument pack Args through sizeof.... make_indices<N>::type then expands into indices<0,1,2,...,N-1>. It is given as an additional parameter to the implementation function (from the forwarder who just creates a dummy instance), hence argument deduction kicks in on the implementation function's side and puts the generated indices into the argument pack Ns.

The implementation function now has two argument packs with the same size, namely Args and Ns. When expanded through the ellipsis ..., the ellipsis expands the whole expression that it's applied to and it expands all parameter packs in parallel! In the above example that expression is read<Args>(Data, Ns+1), which nicely expands into the OPs pseudo-code.

查看更多
登录 后发表回答