Equivalent to std :: transform for tuples

I need a function that will behave like std::transform for tuples. Basically the functionality that will be implemented is

 template<size_t From, size_t To, class Tuple, class Func> void tuple_transform(Tuple&& source, Tuple&& target, Func f) { // elements <From, To> of `target` ti become `f(si)`, where // si is the corresponding element of `source` }; 

I believe that to implement this I will need to compile the integer range struct, generalize std::index_sequence , and I implemented it here with cti::range . I also believe that this type of compile-time bypass is ideal here:

 template<class Func, class Tuple, size_t...Is> void for_each_in_tuple(Func f, Tuple&& tuple, std::index_sequence<Is...>){ using expander = int[]; (void)expander { 0, ((void)f(std::get<Is>(std::forward<Tuple>(tuple))), 0)... }; } template<class Func, class Tuple> void for_each_in_tuple(Func f, Tuple&& tuple){ for_each_in_tuple(f, std::forward<Tuple>(tuple), std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>()); } 

Can someone help me with the implementation?


Notes. About the type of mutation function

@MohitJain Like the related code (tuple_transform), this is not taken into account ( Func has one type). If this is resolved this way, I could easily expand it by passing the template parameter template<class> class Func and indicate that my conversion types are similar to this

 template<typename T> struct Func { static void apply(T& val) { ... } } 

then inside the body of the tuple transform, each func transform can be called as:

 get<I>(target) = func<typename tuple_element<I, Tuple>::type>::apply(get<I>(source)) 

EDIT

There was just a lightning current @accu 2015. The above was CodeKata at the end of the presentation. I will leave a presentation here , I hope that this will help with any attempts at implementation (I think that almost every necessary tool is required, so we will have more attempts)

+7
c ++ tuples template-meta-programming variadic-templates
source share
2 answers

Here is a solution that uses index_range from here .

 template<size_t SN, size_t DN, class TSrc, class TDest, class Func> void tuple_call_assign(TSrc&& source, TDest& target, Func f) { std::get<DN>(target) = f(std::get<SN>(std::forward<TSrc>(source))); } template<size_t From, size_t To, class TSrc, class TDest, class Func, size_t...Is, size_t...DIs> void tuple_transform(TSrc&& source, TDest& target, Func f, std::index_sequence<Is...>, std::index_sequence<DIs...>) { using expander = int[]; (void)expander { 0, (tuple_call_assign<Is,DIs>(std::forward<TSrc>(source),target,f), 0)... }; } template<size_t From, size_t To, size_t FromDest, class TSrc, class TDest, class Func> void tuple_transform(TSrc&& source, TDest& target, Func f) { static_assert(To > From, "Range must be increasing"); static_assert(To <= std::tuple_size<std::decay_t<TSrc>>::value+1, "Range must be valid for source tuple"); constexpr size_t RangeSize = To-From; static_assert(FromDest+RangeSize <= std::tuple_size<std::decay_t<TDest>>::value, "Range must be valid for target tuple"); tuple_transform<From,To>(std::forward<TSrc>(source), target, f, index_range<From,To>(), index_range<FromDest, FromDest+RangeSize>()); } 

Demo

This takes the third argument of the template to indicate the starting index to convert to the target set.

+4
source share

The index_sequence solution index_sequence already been mentioned:

 template <std::size_t From, size_t... indices, typename T1, typename T2, typename Func> void transform(T1&& s, T2& t, Func f, std::index_sequence<indices...>) { (void)std::initializer_list<int>{ (std::get<indices+From>(t) = f(std::get<indices>(std::forward<T1>(s))), 0)...}; } template <std::size_t From, std::size_t To, typename T1, typename T2, typename Func> void transform(T1&& s, T2& t, Func f) { transform<From>(std::forward<T1>(s), t, f, std::make_index_sequence<To-From+1>()); } 

Demo

+1
source share

All Articles