1

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? )

ByteMe95
  • 836
  • 1
  • 6
  • 18

3 Answers3

2

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
mpark
  • 7,574
  • 2
  • 16
  • 18
1
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 just write notstd::apply. It is a bit annoying, but there are dozens of implementations on SO.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
0

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>() );
}
ByteMe95
  • 836
  • 1
  • 6
  • 18