ByteMe95
ByteMe95

Reputation: 876

Simplest way to have a make_tuple method to take a tuple and func and return a mapped tuple

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

Answers (3)

ByteMe95
ByteMe95

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

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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

Upvotes: 1

mpark
mpark

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

Related Questions