0

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), ...)
tambre
  • 4,625
  • 4
  • 42
  • 55
  • I'm not understanding the question. Can you give an example of what the expanded call should look like (say, what `call` would expand to?) – T.C. Mar 25 '16 at 19:29
  • @T.C. you took the words right out of my mouth. I *think* he wants to build an object that contains tuples of (arg, index)... which to me just sounds like a `tuple()` or `std::forward_as_tuple()` ? – Richard Hodges Mar 25 '16 at 19:34
  • I have added an example of non-final expansion. The usage is for an emulator that needs to call HLE functions with various arguments (the first argument is always the same, thus Arg0). The bind_argument takes the arguments from registers (or stack) and casts them to the right type. This question is somewhat of a continuation to my [previous question](https://stackoverflow.com/questions/36217632/using-n-arguments-from-args-starting-from-position-m). – tambre Mar 25 '16 at 19:40
  • 2
    perhaps [this](http://coliru.stacked-crooked.com/a/2643ed407c741a1b) – Piotr Skotnicki Mar 25 '16 at 19:44
  • @PiotrSkotnicki That is exactly what I need! You should probably make an answer, so I could accept it. – tambre Mar 25 '16 at 20:17

1 Answers1

1

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

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160