0

I am trying to make a variadic template function that reads elements in order (with an index). The goal is, for example to call the function read_tuple to read two ints with id 0 and 1 (with read_int(0) and read_int(1)).

Here is the code I get so far:

int data[] = {10,20,30,40};

int int_read(int id)
{
    return data[id];
}

template <typename T>
T read(int& index)
{
    index--;
    int value = int_read(index);
    std::cout << "index :" << index << " value: " << value << std::endl;
    return value;
}

template <typename... Args>
std::tuple<Args...> read_tuple()
{
    int index = sizeof...(Args);
    return std::tuple<Args...>(read<Args>(index)...);
}

I can call it like that:

auto tuple = read_tuple<int, int>();
std::cout << "First: " << std::get<0>(tuple) << std::endl;

And I get the following output:

index :1 value: 20
index :0 value: 10
First: 10

However, this code is dependent of the order of evaluation of the read function. How can I generate an index dependent of the pack expansion (to avoid undefined behavior)?

Manticore
  • 441
  • 5
  • 24
  • 1
    By using a braced-init-list `std::tuple{read(index)...}` you are guaranteed the execution in the order of appearance (i.e. left-to-right) – Piotr Skotnicki Mar 18 '15 at 12:20

1 Answers1

3

As Piotr pointed out, the order of evaluation is garanteed if you use braced-init-list. Be carefull though if you use GCC prior to 4.9.1 as it does not work (c.f. Evaluation order (sequenced-before relation) among initializer-clauses in braced-init-list).

If you use a version that does not garantee the order of initialization (or just want to generate ids) you can use an indexer (from other stackoverflow post):

template<int... I> struct index {
    template<int n> using append = index<I..., n>;
};
template<int N> struct make_index {
    typedef typename make_index<N - 1>::type::template append<N - 1> type;
};
template<> struct make_index<0> { typedef index<> type; };
template<int N> using indexer = typename make_index<N>::type;

You can use it like that:

int data[] = {10,20,30,40};

int int_read(int id)
{
    return data[id];
}

template <typename T>
T read(int index)
{
    int value = int_read(index);
    std::cout << "index :" << index << " value: " << value << std::endl;
    return value;
}

template <typename... Args, int... i>
std::tuple<Args...> read_tuple_indexed(index<i...>)
{
    return std::tuple<Args...>(read<Args>(i)...);
}

template <typename... Args>
std::tuple<Args...> read_tuple()
{
    return read_tuple_indexed<Args...>(indexer<(sizeof...(Args))>());
}
Community
  • 1
  • 1
slepasteur
  • 186
  • 1
  • 11