tambre
tambre

Reputation: 4853

Variadic template indexed pack expansion

Assume the following templates:

template<typename T, bool stack>
struct bind_argument
{
    static inline T get_arg(Object& obj, u8 index)
    {
        return ...;
    }
};

template<typename RT, typename Arg0, typename... Args>
inline RT call(Object& obj, RT(*function)(Arg0, Args...))
{
    constexpr bool use_stack = ...;
    return function(..., bind_argument<Args, use_stack>::get_arg(obj, 0)...);
}

For bind_argument I need to pass the index of the expansion. Another question regarding the indexed expansion showcased the use of the "indices trick" using another template, but in my case I also need to pass the expanded arguments to the call of the function in the call method. This seems to be quite a bit harder than I thought.

My original solution using the "indices trick" looked like this:

template<bool stack, typename... Args, u64... Indices>
struct bind_arguments
{
    static inline Args get_args(CPU& cpu, indices<Indices...>)
    {
        return bind_argument<Args, stack>(cpu, Indices)...;
    }
};

template<typename RT, typename Arg0, typename... Args>
inline RT call(Object& obj, RT(*function)(Arg0, Args...))
{
    constexpr bool use_stack = ...;
    Arg0 some_value = ...;
    return function(some_value, bind_arguments<use_stack, Args...>::get_args(obj, build_indices<sizeof...(Args)>{}));
}

Unfortunately this is not going to compile. How would one perform template indexed pack expansion inside another template and after that passing the expanded values to the place intended for the expanded values? (in this case the function() call)

The intended call expansion would be as follows:

function(some_value, bind_argument<A1, use_stack>(obj, 0), bind_argument<A2, use_stack>(obj, 1), bind_argument<A3, use_stack>(obj, 2), ...)

Upvotes: 0

Views: 284

Answers (1)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48467

You can do whatever you want in that other function, forwarding all necessary arguments; there's no reason to return anything but the final result:

#include <utility>
#include <cstddef>

template <typename RT, typename Arg0, typename... Args, std::size_t... Is>
inline RT call(Object& obj, RT(*function)(Arg0, Args...), std::index_sequence<Is...>)
{
    return function(&obj, bind_argument<Args>::get_arg(obj, Is)...);
}

template <typename RT, typename Arg0, typename... Args>
inline RT call(Object& obj, RT(*function)(Arg0, Args...))
{
    return call(obj, function, std::make_index_sequence<sizeof...(Args)>{});
}

DEMO

Upvotes: 1

Related Questions