forked from boostorg/mp11
Squash-merge PR #50
This commit is contained in:
@@ -13,6 +13,7 @@ http://www.boost.org/LICENSE_1_0.txt
|
|||||||
## Changes in 1.74.0
|
## Changes in 1.74.0
|
||||||
|
|
||||||
* Improve compilation performance of `mp_with_index<N>` for large `N`
|
* Improve compilation performance of `mp_with_index<N>` for large `N`
|
||||||
|
* Added `tuple_transform` (contributed by Hans Dembinski)
|
||||||
|
|
||||||
## Changes in 1.73.0
|
## Changes in 1.73.0
|
||||||
|
|
||||||
|
@@ -36,3 +36,15 @@ The name of the function doesn't match the {cpp}17 one to avoid ambiguities when
|
|||||||
expression `f(std::get<J>(std::forward<Tp>(tp)))` for `J` in 0..`N-1`, where `N` is `std::tuple_size<typename std::remove_reference<Tp>::type>::value`.
|
expression `f(std::get<J>(std::forward<Tp>(tp)))` for `J` in 0..`N-1`, where `N` is `std::tuple_size<typename std::remove_reference<Tp>::type>::value`.
|
||||||
|
|
||||||
Returns `std::forward<F>(f)`.
|
Returns `std::forward<F>(f)`.
|
||||||
|
|
||||||
|
## tuple_transform(f, tp)
|
||||||
|
|
||||||
|
template<class F, class... Tps> constexpr /*...*/ tuple_transform(F const& f, Tps const&... tps);
|
||||||
|
|
||||||
|
`tuple_transform(f, tps...)` 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.
|
||||||
|
@@ -86,6 +86,83 @@ template<class Tp, class F> BOOST_MP11_CONSTEXPR F tuple_for_each( Tp && tp, F &
|
|||||||
return detail::tuple_for_each_impl( std::forward<Tp>(tp), seq(), std::forward<F>(f) );
|
return detail::tuple_for_each_impl( std::forward<Tp>(tp), seq(), std::forward<F>(f) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tuple_transform
|
||||||
|
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...>)
|
||||||
|
{
|
||||||
|
return R( c(std::integral_constant<std::size_t, J>{}, Seq{})... );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // 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{}
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return detail::tuple_transform_impl(
|
||||||
|
detail::tuple_transform_caller<Tp, F, Tps...>{ tp, f, tps... }, Seq{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mp11
|
} // namespace mp11
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
@@ -156,6 +156,8 @@ run tuple_apply.cpp ;
|
|||||||
compile tuple_apply_cx.cpp ;
|
compile tuple_apply_cx.cpp ;
|
||||||
run construct_from_tuple.cpp ;
|
run construct_from_tuple.cpp ;
|
||||||
compile construct_from_tuple_cx.cpp ;
|
compile construct_from_tuple_cx.cpp ;
|
||||||
|
run tuple_transform.cpp ;
|
||||||
|
compile tuple_transform_cx.cpp ;
|
||||||
|
|
||||||
# set
|
# set
|
||||||
run mp_set_contains.cpp ;
|
run mp_set_contains.cpp ;
|
||||||
|
190
test/tuple_transform.cpp
Normal file
190
test/tuple_transform.cpp
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
|
||||||
|
// Copyright 2020 Hans Dembinski.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
//
|
||||||
|
// See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/mp11/tuple.hpp>
|
||||||
|
#include <boost/core/lightweight_test.hpp>
|
||||||
|
#include <boost/core/lightweight_test_trait.hpp>
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
// family of test types with state
|
||||||
|
template <int N>
|
||||||
|
struct T {
|
||||||
|
int value;
|
||||||
|
T() : value{N} {};
|
||||||
|
explicit T(int n) : value{n} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
std::ostream& operator<<( std::ostream& os, T<N> const& t )
|
||||||
|
{
|
||||||
|
os << t.value;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
// test function changes type and value
|
||||||
|
struct F {
|
||||||
|
template<int N, int M=1> T<N+M> operator()( T<N> a, T<M> b={} ) const
|
||||||
|
{
|
||||||
|
return T<N+M>{a.value + b.value + 1};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::mp11::tuple_transform;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<1>, T<2>, T<3>> tp;
|
||||||
|
std::tuple<T<4>, T<5>, T<6>> tp2;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<2>, T<3>, T<4>> s = tuple_transform( F{}, tp );
|
||||||
|
BOOST_TEST_EQ( std::get<0>(s).value, 3 );
|
||||||
|
BOOST_TEST_EQ( std::get<1>(s).value, 4 );
|
||||||
|
BOOST_TEST_EQ( std::get<2>(s).value, 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<2>, T<3>, T<4>> 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 );
|
||||||
|
BOOST_TEST_EQ( std::get<2>(s).value, 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<5>, T<7>, T<9>> s = tuple_transform( F{}, tp, tp2 );
|
||||||
|
BOOST_TEST_EQ( std::get<0>(s).value, 6 );
|
||||||
|
BOOST_TEST_EQ( std::get<1>(s).value, 8 );
|
||||||
|
BOOST_TEST_EQ( std::get<2>(s).value, 10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<5>, T<7>, T<9>> s = tuple_transform(
|
||||||
|
F{}, std::move(tp), std::move(tp2)
|
||||||
|
);
|
||||||
|
BOOST_TEST_EQ( std::get<0>(s).value, 6 );
|
||||||
|
BOOST_TEST_EQ( std::get<1>(s).value, 8 );
|
||||||
|
BOOST_TEST_EQ( std::get<2>(s).value, 10 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<1>, T<2>, T<3>> const tp;
|
||||||
|
std::tuple<T<4>, T<5>, T<6>> const tp2;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<2>, T<3>, T<4>> s = tuple_transform( F{}, tp );
|
||||||
|
BOOST_TEST_EQ( std::get<0>(s).value, 3 );
|
||||||
|
BOOST_TEST_EQ( std::get<1>(s).value, 4 );
|
||||||
|
BOOST_TEST_EQ( std::get<2>(s).value, 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<2>, T<3>, T<4>> 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 );
|
||||||
|
BOOST_TEST_EQ( std::get<2>(s).value, 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<5>, T<7>, T<9>> s = tuple_transform( F{}, tp, tp2 );
|
||||||
|
BOOST_TEST_EQ( std::get<0>(s).value, 6 );
|
||||||
|
BOOST_TEST_EQ( std::get<1>(s).value, 8 );
|
||||||
|
BOOST_TEST_EQ( std::get<2>(s).value, 10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<T<5>, T<7>, T<9>> s = tuple_transform(
|
||||||
|
F{}, std::move(tp), std::move(tp2)
|
||||||
|
);
|
||||||
|
BOOST_TEST_EQ( std::get<0>(s).value, 6 );
|
||||||
|
BOOST_TEST_EQ( std::get<1>(s).value, 8 );
|
||||||
|
BOOST_TEST_EQ( std::get<2>(s).value, 10 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::pair<T<1>, T<2>> tp;
|
||||||
|
std::pair<T<3>, T<4>> tp2;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::pair<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) );
|
||||||
|
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 );
|
||||||
|
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(
|
||||||
|
F{}, std::move(tp), std::move(tp2)
|
||||||
|
);
|
||||||
|
BOOST_TEST_EQ( std::get<0>(s).value, 5 );
|
||||||
|
BOOST_TEST_EQ( std::get<1>(s).value, 7 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::pair<T<1>, T<2>> const tp;
|
||||||
|
std::pair<T<3>, T<4>> const tp2;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::pair<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) );
|
||||||
|
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 );
|
||||||
|
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(
|
||||||
|
F{}, std::move(tp), std::move(tp2)
|
||||||
|
);
|
||||||
|
BOOST_TEST_EQ( std::get<0>(s).value, 5 );
|
||||||
|
BOOST_TEST_EQ( std::get<1>(s).value, 7 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::tuple<> tp;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = tuple_transform( F{}, tp );
|
||||||
|
BOOST_TEST_TRAIT_TRUE((std::is_same<decltype(s), std::tuple<>>));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s = tuple_transform( F{}, std::move(tp) );
|
||||||
|
BOOST_TEST_TRAIT_TRUE((std::is_same<decltype(s), std::tuple<>>));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
75
test/tuple_transform_cx.cpp
Normal file
75
test/tuple_transform_cx.cpp
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
// Copyright 2020 Hans Dembinski.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
//
|
||||||
|
// See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/mp11/tuple.hpp>
|
||||||
|
#include <boost/mp11/detail/config.hpp>
|
||||||
|
|
||||||
|
// Technically std::tuple isn't constexpr enabled in C++11, but it works with libstdc++
|
||||||
|
|
||||||
|
#if defined( BOOST_MP11_NO_CONSTEXPR ) || ( !defined( __GLIBCXX__ ) && __cplusplus < 201400L )
|
||||||
|
|
||||||
|
int main() {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
// family of test types with state
|
||||||
|
template <int N>
|
||||||
|
struct T {
|
||||||
|
int value;
|
||||||
|
constexpr T() : value{N} {};
|
||||||
|
constexpr explicit T(int n) : value{n} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct F
|
||||||
|
{
|
||||||
|
template<int N, int M=1> constexpr T<N+M> operator()( T<N> a, T<M> b={} ) const
|
||||||
|
{
|
||||||
|
return T<N+M>{a.value + b.value + 1};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
constexpr std::tuple<T<1>, T<2>> tp;
|
||||||
|
constexpr std::tuple<T<3>, T<4>> tp2;
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr std::tuple<T<2>, T<3>> r = boost::mp11::tuple_transform(
|
||||||
|
F{}, tp
|
||||||
|
);
|
||||||
|
static_assert(std::get<0>(r).value == 3, "get<0>(r).value == 3" );
|
||||||
|
static_assert(std::get<1>(r).value == 4, "get<1>(r).value == 4" );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr std::tuple<T<4>, T<6>> r = boost::mp11::tuple_transform(
|
||||||
|
F{}, tp, tp2
|
||||||
|
);
|
||||||
|
static_assert(std::get<0>(r).value == 5, "get<0>(r).value == 5" );
|
||||||
|
static_assert(std::get<1>(r).value == 7, "get<1>(r).value == 7" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined( __clang_major__ ) && __clang_major__ == 3 && __clang_minor__ < 9
|
||||||
|
// "error: default initialization of an object of const type 'const std::tuple<>' without a user-provided default constructor"
|
||||||
|
#else
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr std::tuple<> tp;
|
||||||
|
constexpr std::tuple<> r = boost::mp11::tuple_transform( F{}, tp );
|
||||||
|
(void)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user