I have an object of class A
that may be called with different types and returns changed self on each call. For purpose of this question A
will do
struct A {
A call(const int&) {
}
A call(const string& s) {
}
////
} a;
So I have a tuple of unknown types:
std::tuple<Types...> t;
and I want to call a
with each tuple element, so I want to get something like:
b = a;
b = b.call(get<0>(t));
b = b.call(get<1>(t));
b = b.call(get<2>(t));
//...
or
b = a.call(get<0>(t)).call(get<1>(t)).call(get<2>(t)...)
Order is not really important (I mean if call order is reversed of even shuffled it's OK).
I do understand that it's possible to do with recursion but it's quite ugly. Is it possible to achieve without recursion?
You may use std::index_sequence<Is...>
, something like:
namespace detail
{
template <std::size_t...Is, typename T>
void a_call(A& a, std::index_sequence<Is...>, const T& t)
{
int dummy[] = {0, ((a = a.call(std::get<Is>(t))), void(), 0)...};
static_cast<void>(dummy); // Avoid warning for unused variable.
}
}
template <typename ... Ts>
void a_call(A& a, const std::tuple<Ts...>& t)
{
detail::a_call(a, std::index_sequence_for<Ts...>{}, t);
}
In C++17, Folding expression allows:
template <std::size_t...Is, typename T>
void a_call(A& a, std::index_sequence<Is...>, const T& t)
{
(static_cast<void>(a = a.call(std::get<Is>(t))), ...);
}
or even, with std::apply
:
template <typename ... Ts>
void a_call(A& a, const std::tuple<Ts...>& t)
{
std::apply([&](const auto&... args){ (static_cast<void>(a = a.call(args)), ...); }, t);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With