mercredi 11 mars 2020

What is the simplest way to process the values of a template parameter pack in the correct order without using fold-expressions (C++11)

I would like to back-port the following code to C++11:

template<unsigned i>
static void bar() { /* some code with compile-time optimizations for each value i */ }

template <unsigned... I>
void f()
{
  ((bar<I>()),...);
}

The order of invocation of 'bar' for each value of the parameter pack I is important - which I believe is working in the C++17 implementation above because the fold-expression is using the comma operator.

I initially went for an explicitly recursive implementation:

template <unsigned... I>
typename std::enable_if<sizeof...(I) == 0>::type g() {}

template <unsigned head, unsigned... I>
void g()
{
  bar<head>();
  g<I...>();
}

Which seems to work but requires two implementations for g(). While trying to get down to a single function, I read that the pack expansion would happen in make_tuple and thought that this would work:

template<unsigned... I>
static void h1()
{
    std::make_tuple( (bar<I>(), 0)... );
}

unfortunately, this won't provide any guaranty on the order of execution - in fact with gcc the execution order is exactly the inverse. Alternatively, I could use a braced-init-list:

template<unsigned... I>
static void h2()
{
  using expand = int[];
  expand{ 0, ( bar<I>(), 0) ... };
}

This seems to preserve the order with gcc but I couldn't really figure out if this is only a coincidence.

So, the specific questions are:

  • will the implementation of h2 guaranty the correct execution order?
  • are there alternative implementations that I missed?

Aucun commentaire:

Enregistrer un commentaire