How can you iterate over the elements of an std::tuple?
Boost.Fusion is a possibility:
Untested example:
struct DoSomething
{
template<typename T>
void operator()(T& t) const
{
t.do_sth();
}
};
tuple<....> t = ...;
boost::fusion::for_each(t, DoSomething());
Iterate over types of tuple in C++
You can use std::tuple_size
and std::tuple_element
to get the type of every tuple element (this will put it in reverse order, but with a little modification you can revert the order):
#include <iostream>
#include <variant>
#include <vector>
using namespace std;
using Controllers = tuple<int, char, float>;
using ControllersContainer = vector<variant<int, char, float>>;
template <size_t N>
void add(ControllersContainer& ctrls)
{
ctrls.emplace_back(tuple_element_t<N-1, Controllers>{});
add<N - 1>(ctrls);
}
template <>
void add<0>(ControllersContainer& ctrls)
{
ctrls.emplace_back(tuple_element_t<0, Controllers>{});
}
int main()
{
ControllersContainer ctrls;
add<tuple_size_v<Controllers>>(ctrls);
}
Iterating over tuple in C++17/20 [duplicate]
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.
It 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);
How to iterate over a std::tuple in C++ 11 [duplicate]
Here is an attempt to break down iterating over a tuple into component parts.
First, a function that represents doing a sequence of operations in order. Note that many compilers find this hard to understand, despite it being legal C++11 as far as I can tell:
template<class... Fs>
void do_in_order( Fs&&... fs ) {
int unused[] = { 0, ( (void)std::forward<Fs>(fs)(), 0 )... }
(void)unused; // blocks warnings
}
Next, a function that takes a std::tuple
, and extracts the indexes required to access each element. By doing so, we can perfect forward later on.
As a side benefit, my code supports std::pair
and std::array
iteration:
template<class T>
constexpr std::make_index_sequence<std::tuple_size<T>::value>
get_indexes( T const& )
{ return {}; }
The meat and potatoes:
template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
using std::get;
do_in_order( [&]{ f( get<Is>(std::forward<Tuple>(tup)) ); }... );
}
and the public-facing interface:
template<class Tuple, class F>
void for_each( Tuple&& tup, F&& f ) {
auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f) );
}
while it states Tuple
it works on std::array
s and std::pair
s. It also forward the r/l value category of said object down to the function object it invokes. Also note that if you have a free function get<N>
on your custom type, and you override get_indexes
, the above for_each
will work on your custom type.
As noted, do_in_order
while neat isn't supported by many compilers, as they don't like the lambda with unexpanded parameter packs being expanded into parameter packs.
We can inline do_in_order
in that case
template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
using std::get;
int unused[] = { 0, ( (void)f(get<Is>(std::forward<Tuple>(tup)), 0 )... }
(void)unused; // blocks warnings
}
this doesn't cost much verbosity, but I personally find it less clear. The shadow magic of how do_in_order
works is obscured by doing it inline in my opinion.
index_sequence
(and supporting templates) is a C++14 feature that can be written in C++11. Finding such an implementation on stack overflow is easy. A current top google hit is a decent O(lg(n)) depth implementation, which if I read the comments correctly may be the basis for at least one iteration of the actual gcc make_integer_sequence
(the comments also point out some further compile-time improvements surrounding eliminating sizeof...
calls).
Alternatively we can write:
template<class F, class...Args>
void for_each_arg(F&&f,Args&&...args){
using discard=int[];
(void)discard{0,((void)(
f(std::forward<Args>(args))
),0)...};
}
And then:
template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
using std::get;
for_each_arg(
std::forward<F>(f),
get<Is>(std::forward<Tuple>(tup))...
);
}
Which avoids the manual expand yet compiles on more compilers. We pass the Is
via the auto&&i
parameter.
In C++1z we can also use std::apply
with a for_each_arg
function object to do away with the index fiddling.
How to iterate over a tuple of elemenets that have the same base class
You might just using std::apply
:
std::apply([](auto&...args){ (args.call_base_method(), ...); }, tuple);
Else to answer your question, you might do something like:
template <std::size_t... Is, typename tuple_type>
my_class_base& at_impl(std::index_sequence<Is...>, tuple_type& tuple, size_t n)
{
my_class_base* bases[] = {&std::get<Is>(tuple)...};
*return bases[n];
}
template <typename tuple_type>
my_class_base& at(tuple_type& tuple, size_t n)
{
auto seq = std::make_index_sequence<std::tuple_size<tuple_type>::value>();
return at_impl(seq, tuple, n);
}
Demo
Iterate over tuple elements with std::apply
The order in which the arguments to your inner, empty lambda [](...){}
are evaluated is unspecified (even after the paper on evaluation order).
Just use a fold on the comma operator:
std::apply([](auto&&... xs) {
((std::cout << std::forward<decltype(xs)>(xs) << '\n'), ...); },
std::make_tuple(1, 2.f, 3.0));
Demo. Or binary-fold over cout
directly. Once we introduce an "packize" operator, for which there's a proposal out already (using [:]
), you could also write (std::cout << [:]tup << '\n'), ...
.
Related Topics
Calling Virtual Functions Inside Constructors
Can Num++ Be Atomic For 'Int Num'
When Does Invoking a Member Function on a Null Instance Result in Undefined Behavior
Difference Between 'Struct' and 'Typedef Struct' in C++
Cout ≪≪ With Char* Argument Prints String, Not Pointer Value
Definitive List of Common Reasons For Segmentation Faults
C++ Delete - It Deletes My Objects But I Can Still Access the Data
Why Is Integer Assignment on a Naturally Aligned Variable Atomic on X86
Read Whole Ascii File into C++ Std::String
How to Initialize Private Static Members in C++
Function Pointer to Member Function
System("Pause"); - Why Is It Wrong
Opengl - Vertex Normals in Obj
How to Add Reflection to a C++ Application
Why Don't I Get a Segmentation Fault When I Write Beyond the End of an Array