1
0
forked from boostorg/mp11

Replace implementation of tuple_transform

This commit is contained in:
Peter Dimov
2020-05-23 20:00:12 +03:00
parent dcf0d7ebdf
commit c51f83c25a
3 changed files with 37 additions and 81 deletions

View File

@ -37,14 +37,14 @@ expression `f(std::get<J>(std::forward<Tp>(tp)))` for `J` in 0..`N-1`, where `N`
Returns `std::forward<F>(f)`.
## tuple_transform(f, tp)
## tuple_transform(f, tp...)
template<class F, class... Tps> constexpr /*...*/ tuple_transform(F const& f, Tps const&... tps);
template<class F, class... Tp> constexpr /*...*/ tuple_transform(F const& f, Tp&&... tp);
`tuple_transform(f, tps...)` accepts a function object `f` followed by one or more tuples of equal length
`tuple_transform(f, tp...)` accepts a function object `f` followed by one or more tuples of equal length
(`std::pair` is also accepted). The callable `f` must accept as many arguments as there are tuples. The
function object is called with the first elements of each tuple, then with the second element of each tuple,
and so on, by evaluating the expression `f(std::get<J>(tps)...)` for `J` in 0..`N-1`, where `N` is
`std::tuple_size<Tp>::value` for the first tuple `Tp`. The results are returned as a `Tp<Ts...>` with `Ts...`
deduced from the return values of `f`. Warning: The order in which the elements of the tuples are processed
is undefined. Calling `f` should not have side-effects.
and so on, by evaluating the expression `f(std::get<J>(std::forward<Tp>(tp))...)` for `J` in 0..`N-1`, where
`N` is the length of the tuples. The results are returned as a `std::tuple<T...>` with `T...` deduced from the
return values of `f`. The order in which the elements of the tuples are processed is unspecified. Calling `f`
should not have side effects.

View File

@ -1,7 +1,7 @@
#ifndef BOOST_MP11_TUPLE_HPP_INCLUDED
#define BOOST_MP11_TUPLE_HPP_INCLUDED
// Copyright 2015, 2017 Peter Dimov.
// Copyright 2015-2020 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
@ -90,77 +90,33 @@ template<class Tp, class F> BOOST_MP11_CONSTEXPR F tuple_for_each( Tp && tp, F &
namespace detail
{
template <class Tp, class F, class... Tps>
struct tuple_transform_caller {
F const& f_;
std::tuple<Tp const&, Tps const&...> const tps_;
BOOST_MP11_CONSTEXPR tuple_transform_caller( Tp const& tp, F const& f, Tps const&... tps )
: f_{f}, tps_{tp, tps...} {}
template <std::size_t J, std::size_t... I>
BOOST_MP11_CONSTEXPR auto operator()(
std::integral_constant<std::size_t, J>,
integer_sequence<std::size_t, I...>) const
-> decltype(f_(std::get<J>(std::get<I>(tps_))...))
{
return f_(std::get<J>(std::get<I>(tps_))...);
}
};
template <class Tp, class F>
struct tuple_transform_caller<Tp, F> {
F const& f_;
Tp const& tp_;
BOOST_MP11_CONSTEXPR tuple_transform_caller( Tp const& tp, F const& f )
: f_{f}, tp_{tp} {}
template <std::size_t J>
BOOST_MP11_CONSTEXPR auto operator()(
std::integral_constant<std::size_t, J>,
integer_sequence<std::size_t, 0>
) const
-> decltype(f_(std::get<J>(tp_)))
{
return f_(std::get<J>(tp_));
}
};
template<
template <class...> class Tp,
class... Ts,
class... Us,
std::size_t... J,
class Seq = make_index_sequence<sizeof...(Us)>, // tuple sequence
class R = Tp<decltype(std::declval<tuple_transform_caller<Tp<Ts...>, Us...>>()(
std::integral_constant<std::size_t, J>{}, Seq{}
))...>
>
BOOST_MP11_CONSTEXPR R tuple_transform_impl(
tuple_transform_caller<Tp<Ts...>, Us...> c,
integer_sequence<std::size_t, J...>)
template<std::size_t J, class... Tp>
BOOST_MP11_CONSTEXPR auto tp_extract( Tp&&... tp )
-> decltype( std::forward_as_tuple( std::get<J>( std::forward<Tp>( tp ) )... ) )
{
return R( c(std::integral_constant<std::size_t, J>{}, Seq{})... );
return std::forward_as_tuple( std::get<J>( std::forward<Tp>( tp ) )... );
}
template<class... T> BOOST_MP11_CONSTEXPR auto tp_forward( T&&... t ) -> std::tuple<T...>
{
return std::tuple<T...>( std::forward<T>( t )... );
}
template<class F, class... Tp, std::size_t... J>
BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence<std::size_t, J...>, F const& f, Tp&&... tp )
-> decltype( tp_forward( tuple_apply( f, tp_extract<J>( std::forward<Tp>(tp)... ) )... ) )
{
return tp_forward( tuple_apply( f, tp_extract<J>( std::forward<Tp>(tp)... ) )... );
}
} // namespace detail
// warning: evaluation order is undefined
template<
class F,
class Tp,
class... Tps,
class Seq = make_index_sequence<std::tuple_size<Tp>::value> // element sequence
>
BOOST_MP11_CONSTEXPR auto tuple_transform( F const& f, Tp const& tp, Tps const&... tps )
-> decltype(detail::tuple_transform_impl(
std::declval<detail::tuple_transform_caller<Tp, F, Tps...>>(), Seq{}
))
template<class F, class Tp1, class... Tp,
class Seq = make_index_sequence<std::tuple_size<typename std::remove_reference<Tp1>::type>::value>>
BOOST_MP11_CONSTEXPR auto tuple_transform( F const& f, Tp1&& tp1, Tp&&... tp )
-> decltype( detail::tuple_transform_impl( Seq(), f, std::forward<Tp1>(tp1), std::forward<Tp>(tp)... ) )
{
return detail::tuple_transform_impl(
detail::tuple_transform_caller<Tp, F, Tps...>{ tp, f, tps... }, Seq{}
);
return detail::tuple_transform_impl( Seq(), f, std::forward<Tp1>(tp1), std::forward<Tp>(tp)... );
}
} // namespace mp11

View File

@ -115,25 +115,25 @@ int main()
std::pair<T<3>, T<4>> tp2;
{
std::pair<T<2>, T<3>> s = tuple_transform( F{}, tp );
std::tuple<T<2>, T<3>> s = tuple_transform( F{}, tp );
BOOST_TEST_EQ( std::get<0>(s).value, 3 );
BOOST_TEST_EQ( std::get<1>(s).value, 4 );
}
{
std::pair<T<2>, T<3>> s = tuple_transform( F{}, std::move(tp) );
std::tuple<T<2>, T<3>> s = tuple_transform( F{}, std::move(tp) );
BOOST_TEST_EQ( std::get<0>(s).value, 3 );
BOOST_TEST_EQ( std::get<1>(s).value, 4 );
}
{
std::pair<T<4>, T<6>> s = tuple_transform( F{}, tp, tp2 );
std::tuple<T<4>, T<6>> s = tuple_transform( F{}, tp, tp2 );
BOOST_TEST_EQ( std::get<0>(s).value, 5 );
BOOST_TEST_EQ( std::get<1>(s).value, 7 );
}
{
std::pair<T<4>, T<6>> s = tuple_transform(
std::tuple<T<4>, T<6>> s = tuple_transform(
F{}, std::move(tp), std::move(tp2)
);
BOOST_TEST_EQ( std::get<0>(s).value, 5 );
@ -146,25 +146,25 @@ int main()
std::pair<T<3>, T<4>> const tp2;
{
std::pair<T<2>, T<3>> s = tuple_transform( F{}, tp );
std::tuple<T<2>, T<3>> s = tuple_transform( F{}, tp );
BOOST_TEST_EQ( std::get<0>(s).value, 3 );
BOOST_TEST_EQ( std::get<1>(s).value, 4 );
}
{
std::pair<T<2>, T<3>> s = tuple_transform( F{}, std::move(tp) );
std::tuple<T<2>, T<3>> s = tuple_transform( F{}, std::move(tp) );
BOOST_TEST_EQ( std::get<0>(s).value, 3 );
BOOST_TEST_EQ( std::get<1>(s).value, 4 );
}
{
std::pair<T<4>, T<6>> s = tuple_transform( F{}, tp, tp2 );
std::tuple<T<4>, T<6>> s = tuple_transform( F{}, tp, tp2 );
BOOST_TEST_EQ( std::get<0>(s).value, 5 );
BOOST_TEST_EQ( std::get<1>(s).value, 7 );
}
{
std::pair<T<4>, T<6>> s = tuple_transform(
std::tuple<T<4>, T<6>> s = tuple_transform(
F{}, std::move(tp), std::move(tp2)
);
BOOST_TEST_EQ( std::get<0>(s).value, 5 );