With C++1z it's pretty simple with fold expressions. First, forward the tuple to an _impl
function and provide it with index sequence to access all tuple elements, then sum:
template<typename T, size_t... Is>
auto sum_components_impl(T const& t, std::index_sequence<Is...>)
{
return (std::get<Is>(t) + ...);
}
template <class Tuple>
int sum_components(const Tuple& t)
{
constexpr auto size = std::tuple_size<Tuple>{};
return sum_components_impl(t, std::make_index_sequence<size>{});
}
demo
A C++14 approach would be to recursively sum a variadic pack:
int sum()
{
return 0;
}
template<typename T, typename... Us>
auto sum(T&& t, Us&&... us)
{
return std::forward<T>(t) + sum(std::forward<Us>(us)...);
}
template<typename T, size_t... Is>
auto sum_components_impl(T const& t, std::index_sequence<Is...>)
{
return sum(std::get<Is>(t)...);
}
template <class Tuple>
int sum_components(const Tuple& t)
{
constexpr auto size = std::tuple_size<Tuple>{};
return sum_components_impl(t, std::make_index_sequence<size>{});
}
demo
A C++11 approach would be the C++14 approach with custom implementation of index_sequence
. For example from here.
As @ildjarn pointed out in the comments, the above examples are both employing right folds, while many programmers expect left folds in their code. The C++1z version is trivially changeable:
template<typename T, size_t... Is>
auto sum_components_impl(T const& t, std::index_sequence<Is...>)
{
return (... + std::get<Is>(t));
}
demo
And the C++14 isn't much worse, but there are more changes:
template<typename T, typename... Us>
auto sum(T&& t, Us&&... us)
{
return sum(std::forward<Us>(us)...) + std::forward<T>(t);
}
template<typename T, size_t... Is>
auto sum_components_impl(T const& t, std::index_sequence<Is...>)
{
constexpr auto last_index = sizeof...(Is) - 1;
return sum(std::get<last_index - Is>(t)...);
}
demo