Consider a tuple t
of n objects with similar interface (like all have the same base class); n is known during compilation. I need to make a sum as following
std::get<0>(t).foo(vec_0) + std::get<1>(t).foo(vec_1) + ... + std::get<n>(t).foo(vec_n)
I know to add elements of a tuple of numbers, like here, and even variable\functions of an objects in a tuple, e.g.
std::get<0>(t).bar()+std::get<1>(t).bar()...
The situation that I still interesting to find a (template) solution for is the following one:
vec_0,...,vec_n
are different size slices of a bigger vector Vec
.std::get<0>(t).foo(Vec.head(std::get<0>(t).n)) +
std::get<1>(t).foo(Vec.segment(std::get<0>(t).n, std::get<1>(t).n))+
std::get<2>(t).foo(Vec.segment(std::get<0>(t).n + std::get<1>(t).n, std::get<2>(t).n))+
... +
std::get<n>(t).foo(Vec.tail(std::get<n>(t).n))
Here segment
takes (start, size)
and return required vector; the size is known from std::get<?>(t).n
.
You just need extra std::index_sequence
usage for the inner elements, something like:
template <std::size_t ... Is, typename Tuple, typename Vec>
auto helper(std::index_sequence<Is...>, const Tuple& t, const Vec& vec)
{
constexpr auto N = sizeof...(Is);
constexpr auto Size = std::tuple_size<Tuple>::value;
if constexpr (Size == 1) {
// Unsure what you want here
return std::get<0>(t).foo(Vec.head(std::get<0>(t).n))
+ std::get<N>(t).foo(Vec.tail(std::get<0>(t).n));
} else if constexpr (N == 0) {
return std::get<0>(t).foo(Vec.head(std::get<0>(t).n));
} else if constexpr (N + 1 == Size) {
return std::get<N>(t).foo(Vec.tail(std::get<N>(t).n));
} else {
return std::get<N>(t).foo(Vec.segment((0 + ... + std::get<Is>(t).n),
std::get<N>(t).n));
}
}
template <std::size_t ... Is, typename Tuple, typename Vec>
auto summation(std::index_sequence<Is...>, const Tuple& t, const Vec& vec)
{
return (0 + ... + helper(std::make_index_sequence<Is>(), t, vec));
}
template <typename Tuple, typename Vec>
auto summation(const Tuple& t, const Vec& vec)
{
constexpr auto Size = std::tuple_size<Tuple>::value;
return summation(std::make_index_sequence<Size>(), t, vec));
}