2

Given a variadic parameter pack, I would like to call a function with each element and its index in the pack.

I have a simple example below which uses recursive instantiations of a function template to achieve this. (on godbolt)

#include <iostream>
#include <tuple>

template<std::size_t I, typename Tuple>
void foo(Tuple&& tuple)
{
    std::cout << "item " << I << "=" << std::get<I>(tuple) << '\n';

    if constexpr (I + 1 < std::tuple_size_v<std::decay_t<Tuple>>)
        foo<I+1>(tuple);
}

template<typename... Ts>
void bar(Ts... ts)
{
    foo<0>(std::tuple(ts...));
}

int main()
{
    bar(5, 3.14, "hello world", 'c');
    return 0;
}

This works as expected:

item 0=5
item 1=3.14
item 2=hello world
item 3=c

Is it possible to achieve the same result using std::index_sequence and a template fold expression?

Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213

2 Answers2

2

It could be:

template<size_t ... Indices, typename... Ts>
void bar2(std::index_sequence<Indices...>, Ts&&... ts) {
    auto action = [](size_t idx, auto&& arg) { std::cout << "item " << idx << "=" << arg << std::endl; };
    (action(Indices,std::forward<Ts>(ts)),...);
}

template<typename... Ts>
void bar2(Ts&&... ts) {
    bar2(std::make_index_sequence<sizeof...(Ts)>(), std::forward<Ts>(ts)...);
}

Demo

rafix07
  • 20,001
  • 3
  • 20
  • 33
  • 3
    works... but I don't understand the need of the lambda in the first `bar2()`; what about directly using folding? I mean `((std::cout << "item " << Indices << '=' << std::forward(ts) << std::endl), ...);` – max66 Apr 09 '22 at 12:26
1

No need to use std::index_sequence

#include <iostream>

template<typename... Ts>
void bar(Ts&&... ts) {
  std::size_t idx = 0;
  ((std::cout << "item " << idx++ << "=" << ts << '\n'), ...);
}

Demo

If you want I to be a non-type template parameter, then a template lambda is enough

template<typename... Ts>
void bar(Ts&&... ts) {
  [&]<std::size_t... Is>(std::index_sequence<Is...>) {
    ((std::cout << "item " << Is << "=" << ts << '\n'), ...);
  }(std::index_sequence_for<Ts...>{});
}
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • You won't be able to use `idx` as a template parameter though. – super Apr 09 '22 at 11:09
  • In OP's example he passes it to `std::get`, which is not possible with your example. – super Apr 09 '22 at 11:12
  • Doesn't he pass in `std::get` because it wants to extract the element from the tuple? – 康桓瑋 Apr 09 '22 at 11:13
  • It's not really clear exactly why. But it's probably worth mentioning. If not in the answer then at least in the comments. – super Apr 09 '22 at 11:14
  • I understand what you mean. Just based on the call form `bar(5, 3.14, "hello world", 'c')`, I don't think it's necessary to use `tuple`. – 康桓瑋 Apr 09 '22 at 11:17