Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to "duplicate" template parameter pack expansion?

Consider this code:

template < size_t... Indices >
void something(std::index_sequence<Indices...>)
{
  // how to obtain the following call where N is sizeof...(Indices)?
  // foo(f(0),g(0),f(1),g(1),...,f(N-1),g(N-1));
}
like image 846
Vahagn Avatar asked Sep 11 '25 19:09

Vahagn


1 Answers

The key to answering a question like:

// how to obtain the following call where N is sizeof...(Indices)?
// foo(f(0),g(0),f(1),g(1),...,f(N-1),g(N-1));

is to formulate how to actually generate such a pack expansion. We have 2N arguments, which would like:

+=====+======+
| idx | expr |
+-----+------+
|  0  | f(0) |
|  1  | g(0) |
|  2  | f(1) |
|  3  | g(1) |
|   ....
+=====+======+

In C++17, we can write such an expression with if constexpr:

template <size_t I>
auto expr() {
    if constexpr (I % 2 == 0) { 
        // even indices are fs
        return f(I / 2);
    } else {
        // odds are gs
        return g(I / 2);
    }
}

Which can even be a lambda that takes an integral_constant as an argument. So we really just need to turn our N arguments into 2N arguments, which is just a matter of adding more indices:

template <auto V>
using constant = std::integral_constant<decltype(V), V>;

template < size_t... Indices >
void something(std::index_sequence<Indices...>) {
    auto expr = [](auto I) {
        if constexpr (I % 2 == 0) {
            return f(I / 2);
        } else {
            return g(I / 2);
        }
    }

    return foo(
        expr(constant<Indices>{})...,                     // 0, ..., N-1
        expr(constant<Indices + sizeof...(Indices)>{})... // N, ..., 2N-1
    );
}
like image 119
Barry Avatar answered Sep 13 '25 09:09

Barry