I wrote a "foreach" implementation for std::tuple
:
#pragma once
#include <tuple>
/**
* Callback example:
struct Call{
float k=0;
template<typename T, int Index> // lambda function not efficient than this. Tested -O2 clang, gcc 4.8
inline void call(T &&t){
std::cout << t.h << " ; " << "id = " << Index << std::endl;
}
};
*/
namespace TUPLE_ITERATOR{
template<typename Tuple, int index, int size>
struct LOOP{
template <typename Callback>
static inline void wind(Tuple&& tuple, Callback&& callback){
callback.template call<decltype(std::get<index>(tuple)), index> (std::get<index>(tuple));
LOOP<Tuple, index+1, size>::wind( std::forward<Tuple>(tuple), std::forward<Callback>(callback) );
}
};
template<typename Tuple, int size>
struct LOOP_BACK{
template <typename Callback>
static inline void wind_reverse(Tuple&& tuple, Callback&& callback){
callback.template call<decltype(std::get<size>(tuple)), size>( std::get<size>(tuple) );
LOOP_BACK<Tuple, size-1>::wind_reverse( std::forward<Tuple>(tuple), std::forward<Callback>(callback) );
}
};
// stop specialization
template<typename Tuple, int size>
struct LOOP<Tuple, size, size> {
template <typename Callback>
static inline void wind(Tuple&& , Callback&& ){
// end
}
};
template<typename Tuple>
struct LOOP_BACK<Tuple, -1>{
template <typename Callback>
static inline void wind_reverse(Tuple&& , Callback&& ){
// end
}
};
}
template<typename Tuple, typename Callback>
static void inline iterate_tuple(Tuple&& tuple, Callback&& callback){
TUPLE_ITERATOR::LOOP< Tuple, 0, std::tuple_size< typename std::decay<Tuple>::type >::value >
::template wind<Callback>( std::forward<Tuple>(tuple), std::forward<Callback>(callback) );
}
template<typename Tuple, typename Callback>
static void inline iterate_tuple_back(Tuple&& tuple, Callback&& callback){
TUPLE_ITERATOR::LOOP_BACK< Tuple, std::tuple_size< typename std::decay<Tuple>::type >::value-1 >
::template wind_reverse<Callback>( std::forward<Tuple>(tuple), std::forward<Callback>(callback) );
}
// Call:
// iterate_tuple(Callback(), std::make_tuple(1,2,3,"asdaa"));
But I look at how other folks do that, and I see that they do this in another way. They get an array of indices, and then recursively call the callback
function. Is my implementation worse than that? I ask this because if I call tuple_iterator
twice, with the same parameters, the compiler starts to use asm "calls". Look HERE, on the red.
void TUPLE_ITERATOR::LOOP<std::tuple<std::pair<int, Data>,
std::pair<int, Data> >, 0, 2>:
std::integer_sequence
andstd::tuple
to get the equivalent of a loop (though underneath in the standard code it is still recursion it is not visible from my code and thus easier to read). \$\endgroup\$