Jared Hoberock
Jared Hoberock

Reputation: 11406

iterating over tuple's elements in a specified sequential order

It's possible to iterate over a tuple's elements and apply a function with this sort of implementation:

#include <tuple>
#include <utility>

template<class... Args>
void swallow(Args&&...)
{
}

template<size_t... Indices, class Function, class Tuple>
void tuple_for_each_in_unspecified_order_impl(std::index_sequence<Indices...>, Function f, const Tuple& t)
{
  swallow(f(std::get<Indices>(t))...);
}

template<class Function, class... Types>
void tuple_for_each_in_unspecified_order(Function f, const std::tuple<Types...>& t)
{
  tuple_for_each_in_unspecified_order_impl(std::index_sequence_for<Types...>(), f, t);
}

Because this implementation relies on the order of parameters passed to the swallow() function, the order of f's invocations are unspecified.

One way to force the invocations of f to agree with the order of tuple elements would be to use recursion:

template<class Function, class Tuple>
void tuple_for_each_in_order_impl(std::index_sequence<>, Function f, const Tuple& t) {}

template<size_t I, size_t... Indices, class Function, class Tuple>
void tuple_for_each_in_order_impl(std::index_sequence<I,Indices...>, Function f, const Tuple& t)
{
  f(std::get<I>(t));

  tuple_for_each_in_order_impl(std::index_sequence<Indices...>(), f, t);
}

template<class Function, class... Types>
void tuple_for_each_in_order(Function f, const std::tuple<Types...>& t)
{
  tuple_for_each_in_order_impl(std::index_sequence_for<Types...>, f, t);
}

The problem with this recursive solution is that it may introduce disappointing compile-time performance.

Is there a more efficient solution that would produce the desired evaluation order?

I know that many fine c++ libraries for metaprogramming and tuple manipulation are available, but I am interested in the implementation details of a solution, should one exist.

Upvotes: 2

Views: 484

Answers (1)

T.C.
T.C.

Reputation: 137315

In C++1z, fold it over the comma operator:

(... , void(f(get<Indices>(t))));

Before that, unpack into a braced-init-list, e.g.:

auto l = {0, (void(f(get<Indices>(t))), 0)... };
(void) l;

Upvotes: 3

Related Questions