Max Max - 12 days ago 5
C++ Question

Sum the components of a tuple up by using std::get, std::tuple_size, std::tuple_element

I've got a custom class that has a tuple-like interface. Because I want my code to be as generic as possible, I thought that it would be a good idea to base my algorithms on the functions

std::get
,
std::tuple_size
,
std::tuple_element
so you just have to specialize these functions to use my algorithms. Let's call the concept that requires these function specializations
Tuple
.

Now I am trying to sum up the components of a
Tuple
. The function declaration should be something like this:

template <class Tuple>
int sum_components(const Tuple& t);


I guess that there is a lot of template programming involved but I just can't figure out how to do it.

For the addition I would just use an overload of the global
+ operator
.

I am using c++1z.

Answer

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:

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

Comments