Does anyone know of a good, clean way to iterate over a tuple in C++17 / 20? Let's say we have a bit of code like this:
class Test
{
public:
Test( int x ) : x_(x) {};
void Go() const { std::cout << "Hi!" << x_ << "\n" ; }
int x_;
};
int main()
{
std::tuple tplb{ Test{1} , Test{2} , Test{3} };
}
How could we iterate through the tuple and call the Go()
method on each using the latest 17/20 features?
I know you could just have a vector of the object and then it works easily. My goal with this is to be able to ha e a certain polymorphism without having to use virtual functions.
The idea would be to be able to have other object types in the tuple that support the same method. If the method is present in each object then the code would compile and execute without having to use a base-class, virtuals, vtable, etc.
Is there some way perhaps with std::apply
or std::invoke
?
Is there some way perhaps with
std::apply
orstd::invoke
?
std::apply
fit the need indeed with fold expression:
std::tuple tplb{ Test{1} , Test{2} , Test{3} };
std::apply([](const auto&... tests){(tests.Go(), ...);}, tplb);
Here, we call method Go()
for every type value of the tuple
.
The idea would be to be able to have other object types in the tuple that support the same method. If the method is present in each object then the code would compile and execute without having to use a base-class, virtuals, vtable, etc.
So above method works.
If you would go further and dispatch to different implementation according to type, you might use overloaded
class from std::visit's example:
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
auto f = overloaded {
[](const Test& test) { test.Go(); },
[](double d) { std::cout << d << ' '; },
[](const std::string& s) { std::cout << s << ' '; },
};
std::apply([&](const auto&... e){ (f(e), ...);}, my_tuple);