Here is a similar and more verbose solution than the formerly accepted one given by T.C., which is maybe a little bit easier to understand (-- it's probably the same as thousand others out there in the net):
template
void for_each(TupleType&&, FunctionType
, std::integral_constant::type >::value>) {}
template::type>::value>::type >
void for_each(TupleType&& t, FunctionType f, std::integral_constant)
{
f(std::get(std::forward(t)));
for_each(std::forward(t), f, std::integral_constant());
}
template
void for_each(TupleType&& t, FunctionType f)
{
for_each(std::forward(t), f, std::integral_constant());
}
Usage (with std::tuple):
auto some = std::make_tuple("I am good", 255, 2.1);
for_each(some, [](const auto &x) { std::cout << x << std::endl; });
Usage (with std::array):
std::array some2 = {"Also good", "Hello world"};
for_each(some2, [](const auto &x) { std::cout << x << std::endl; });
DEMO
General idea: as in the solution of T.C., start with an index I=0 and go up to the size of the tuple. However, here it is done not per variadic expansion but one-at-a-time.
Explanation:
The first overload of for_each is called if I is equal to the size of the tuple. The function then simply does nothing and such end the recursion.
The second overload calls the function with the argument std::get(t) and increases the index by one. The class std::integral_constant is needed in order to resolve the value of I at compile time. The std::enable_if SFINAE stuff is used to help the compiler separate this overload from the previous one, and call this overload only if the I is smaller than the tuple size (on Coliru this is needed, whereas in Visual Studio it works without).
The third starts the recursion with I=0. It is the overload which is usually called from outside.
EDIT: I've also included the idea mentioned by Yakk to additionally support std::array and std::pair by using a general template parameter TupleType instead of one that is specialized for std::tuple.
As TupleType type needs to be deduced and is such a "universal reference", this further has the advantage that one gets perfect forwarding for free. The downside is that one has to use another indirection via typename std::remove_reference::type, as TupleType might also be a deduced as a reference type.