diff --git a/doc/mp11/tuple.adoc b/doc/mp11/tuple.adoc index b89a73b..4b190f8 100644 --- a/doc/mp11/tuple.adoc +++ b/doc/mp11/tuple.adoc @@ -42,9 +42,15 @@ Returns `std::forward(f)`. template constexpr /*...*/ tuple_transform(F const& f, Tp&&... tp); `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(std::forward(tp))...)` for `J` in 0..`N-1`, where -`N` is the length of the tuples. The results are returned as a `std::tuple` 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. +(`std::tuple`, `std::pair` and `std::array` are considered tuples.) + +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, as if by evaluating +the expression `f(std::get(std::forward(tp))...)` for `J` in 0..`N-1`, where `N` is the length of +the tuples. + +The results are returned as a `std::tuple` with `T...` deduced from the return values of `f` (lvalue +references are preserved, rvalue references are returned by value.) + +The order in which the elements of the tuples are processed is unspecified. Calling `f` should not have +side effects. diff --git a/test/Jamfile b/test/Jamfile index 15fef4c..663d3e5 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -157,6 +157,7 @@ compile tuple_apply_cx.cpp ; run construct_from_tuple.cpp ; compile construct_from_tuple_cx.cpp ; run tuple_transform.cpp ; +run tuple_transform_2.cpp ; compile tuple_transform_cx.cpp ; # set diff --git a/test/tuple_transform_2.cpp b/test/tuple_transform_2.cpp new file mode 100644 index 0000000..a8c04e8 --- /dev/null +++ b/test/tuple_transform_2.cpp @@ -0,0 +1,162 @@ +// Copyright 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include +#include + +int f( int x ) +{ + return x + 1; +} + +int g( int x, int y ) +{ + return x + y; +} + +int h( int x, int y, int z ) +{ + return x + y + z; +} + +int q( int x, int y, int z, int v ) +{ + return x + y + z + v; +} + +template std::array make_array( T1 t1, T... t ) +{ + return { { t1, t... } }; +} + +template struct test_element +{ + Tp& tp; + + template void operator()( boost::mp11::mp_int ) const + { + BOOST_TEST_EQ( std::get( tp ), q( I, I, I, I ) ); + } +}; + +int main() +{ + using boost::mp11::tuple_transform; + + // + + { + std::tuple r = tuple_transform( f, std::make_tuple( 1 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 2 ); + } + + { + std::tuple r = tuple_transform( f, ::make_array( 1 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 2 ); + } + + { + std::tuple r = tuple_transform( g, ::make_array( 1 ), std::make_tuple( 2 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 3 ); + } + + { + std::tuple r = tuple_transform( h, ::make_array( 1 ), std::make_tuple( 2 ), ::make_array( 3 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 6 ); + } + + // + + { + std::tuple r = tuple_transform( f, std::make_tuple( 1, 2 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 2 ); + BOOST_TEST_EQ( std::get<1>( r ), 3 ); + } + + { + std::tuple r = tuple_transform( f, std::make_pair( 1, 2 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 2 ); + BOOST_TEST_EQ( std::get<1>( r ), 3 ); + } + + { + std::tuple r = tuple_transform( f, ::make_array( 1, 2 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 2 ); + BOOST_TEST_EQ( std::get<1>( r ), 3 ); + } + + { + std::tuple r = tuple_transform( g, ::make_array( 1, 2 ), std::make_pair( 3, 4 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 4 ); + BOOST_TEST_EQ( std::get<1>( r ), 6 ); + } + + { + std::tuple r = tuple_transform( h, ::make_array( 1, 2 ), std::make_pair( 3, 4 ), std::make_tuple( 5, 6 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 9 ); + BOOST_TEST_EQ( std::get<1>( r ), 12 ); + } + + // + + { + std::tuple r = tuple_transform( f, std::make_tuple( 1, 2, 3 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 2 ); + BOOST_TEST_EQ( std::get<1>( r ), 3 ); + BOOST_TEST_EQ( std::get<2>( r ), 4 ); + } + + { + std::tuple r = tuple_transform( f, ::make_array( 1, 2, 3 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 2 ); + BOOST_TEST_EQ( std::get<1>( r ), 3 ); + BOOST_TEST_EQ( std::get<2>( r ), 4 ); + } + + { + std::tuple r = tuple_transform( g, ::make_array( 1, 2, 3 ), std::make_tuple( 4, 5, 6 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 5 ); + BOOST_TEST_EQ( std::get<1>( r ), 7 ); + BOOST_TEST_EQ( std::get<2>( r ), 9 ); + } + + { + std::tuple r = tuple_transform( h, ::make_array( 1, 2, 3 ), std::make_tuple( 4, 5, 6 ), ::make_array( 7, 8, 9 ) ); + + BOOST_TEST_EQ( std::get<0>( r ), 12 ); + BOOST_TEST_EQ( std::get<1>( r ), 15 ); + BOOST_TEST_EQ( std::get<2>( r ), 18 ); + } + + { + using namespace boost::mp11; + + int const N = 64; + + using Tp = mp_rename >, std::tuple>; + + auto const r = tuple_transform( q, Tp(), Tp(), Tp(), Tp() ); + + mp_for_each( test_element{ r } ); + } + + return boost::report_errors(); +}