Obtain Argument Index while Unpacking Argument List with Variadic Templates


Answers

The simplest solution is surely to not use a vector of void*; just use the values directly:

template<typename...Arg>
void call_test(Arg const&...arg) {
  test(arg...);
}

(Or some variant on that theme.) But I suppose you wanted to do something other than just call test.

If you really want the indices, use what's called here the "indices trick". You should be able to search for that.

Question

I need to obtain the index of an argument while unpacking and converting argument list. Is there any solution for the following problem:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

void test(int a, std::string b, bool c)
{
    cout << a << "," << b << "," << c << endl ;
}

template <typename... ARG>
static void call_test(const vector<void*> &params)
{
    test(*static_cast<ARG*>(params[ indexOf(ARG) ])...);
}

int main(int argc, char **argv)
{
    int    a = 1;
    string b = "string";
    bool c   = false;
    vector<void*> v(3);
    v[0] = &a;
    v[1] = &b;
    v[2] = &c;

    call_test<int,string,bool>(v);
}



An alternative to all the variadic template juggling is to use the boost::zip_iterator for this purpose. For example (untested):

std::vector<int> ia;
std::vector<double> d;
std::vector<int> ib;

std::for_each(
  boost::make_zip_iterator(
    boost::make_tuple(ia.begin(), d.begin(), ib.begin())
    ),
  boost::make_zip_iterator(
    boost::make_tuple(ia.end(), d.end(), ib.end())
    ),
  handle_each()
  );

Where your handler, looks like:

struct handle_each :
  public std::unary_function<const boost::tuple<const int&, const double&, const int&>&, void>
{
  void operator()(const boost::tuple<const int&, const double&, const int&>& t) const
  {
    // Now you have a tuple of the three values across the vector...
  }
};

As you can see, it's pretty trivial to expand this to support an arbitrary set of vectors..




Following may help:

#if 1 // Not in C++11
#include <cstdint>

template <std::size_t ...> struct index_sequence {};

template <std::size_t N, std::size_t ...Is>
struct make_index_sequence : make_index_sequence <N - 1, N - 1, Is...> {};

template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};

#endif // make_index_sequence


using func = void (*)();

namespace detail
{

// general case
template <std::size_t N>
struct FuncPtr { static constexpr func value = &Nth<N>; };

// Some specializations // not necessary at the beginning
template <>
struct FuncPtr<0u> { static constexpr func value = &zero; };

template <>
struct FuncPtr<1u> { static constexpr func value = &one; };

// Function to create the array:
template <std::size_t ... Is>
constexpr std::array<func, sizeof...(Is)>
FuncPtrArray(index_sequence<Is...>)
{
    return std::array<func, sizeof...(Is)>{{FuncPtr<Is>::value...}};
}

} // namespace detail

constexpr std::array<func, 256> interrupt_vector =
    detail::FuncPtrArray(make_index_sequence<256>());



How can I initialize an array in compile-time with some elements given manually?

If you can change to use std::array then something like this would work.

using func = void (*)();

template<int...>
struct index_sequence { };

template<int From, int N, int... Is>
struct make_index_sequence_from : make_index_sequence_from<From, N - 1, N - 1, Is...> { };

template<int From, int... Is>
struct make_index_sequence_from<From, From, Is...> : index_sequence<Is...> { };

template<int... Is> constexpr
std::array<func, 256> make_interrupt_vector_array(index_sequence<Is...>)
{
    return {{zero, one, Nth<Is>...}};
}

constexpr
std::array<func, 256> make_interrupt_vector_array()
{
    return make_interrupt_vector_array(make_index_sequence_from<2, 256>());
}

constexpr auto interrupt_vector = make_interrupt_vector_array();




Tags