Reputation: 876
Ive been searching for this topic a lot and have failed to find any satisfying answer. Im looking for a method to do what most high level languages can already do, take a tuple and a mapping method and return a mapped ( aka transformed ) tuple. Ideally this would work in c++14, though c++17 is ok if required.
For example:
auto new_tuple = awesome_make_tuple( curtuple, []( auto & v ) { return v - 1; } )
Types can be different but the provided method would have to work for any given type. ( Side Q, can the method be templated somehow? )
Upvotes: 1
Views: 73
Reputation: 876
After playing around a bit more I have come up with this as the simplest approach ( works in c++14 ). Thanks for getting me in the right direction:
template<typename T, typename F, size_t...indices>
auto map_impl( T && in, F && f, std::index_sequence<indices...> )
{
return std::make_tuple( f( std::get<indices>( in ) )... );
}
template<typename T, typename F>
auto map( T && in, F && f )
{
const size_t sz = std::tuple_size<std::decay_t<T>>::value;
return map_impl( std::forward<T>( in ), std::forward<F>( f ), std::make_index_sequence<sz>() );
}
Upvotes: 0
Reputation: 275600
template<class F>
auto tupler(F&&f){
return [f=std::forward<F>(f)](auto&&...args)mutable{
return std::make_tuple( f(decltype(args)(args))... );
};
}
template<class F, class Tup>
auto map_tuple( F&& f, Tup&& tup ){
return std::apply( tupler(std::forward<F>(f)), std::forward<Tup>(tup) );
}
in c++14 just write notstd::apply
. It is a bit annoying, but there are dozens of implementations on SO.
Upvotes: 1
Reputation: 7904
One possible approach is to use std::apply
to unpack the tuple and apply the f
per unpacked element, and rebuild a tuple. Something like:
template <typename Tuple, typename F>
auto tuple_map(const Tuple& t, F f) {
return std::apply([&](auto... args) { return std::make_tuple(f(args)...); }, t);
}
Example usage:
auto t = std::make_tuple(1, 2, 3);
auto mapped = tuple_map(t, [](auto x) { return x - 1; });
std::cout << std::get<0>(mapped) << ' '
<< std::get<1>(mapped) << ' '
<< std::get<2>(mapped) << '\n';
// prints 0 1 2
Upvotes: 2