diff --git a/doc/html/mp11.html b/doc/html/mp11.html index 2b30e0e..12d2697 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -591,6 +591,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • Tuple Operations, <boost/mp11/tuple.hpp>
  • @@ -2809,6 +2810,18 @@ of U…​ and the mp_bind expressions replace

    Tuple Operations, <boost/mp11/tuple.hpp>

    +

    tuple_apply(f, tp)

    +
    +
    +
    template<class F, class Tp> constexpr /*...*/ tuple_apply(F&& f, Tp&& tp);
    +
    +
    +
    +

    tuple_apply(f, tp) returns std::forward<F>(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. Same as std::apply in C++17.

    +
    +
    +

    tuple_for_each(tp, f)

    diff --git a/doc/mp11/tuple.adoc b/doc/mp11/tuple.adoc index 53b8c19..b9dd82c 100644 --- a/doc/mp11/tuple.adoc +++ b/doc/mp11/tuple.adoc @@ -9,8 +9,17 @@ http://www.boost.org/LICENSE_1_0.txt [#tuple] # Tuple Operations, +:toc: +:toc-title: :idprefix: +## tuple_apply(f, tp) + + template constexpr /*...*/ tuple_apply(F&& f, Tp&& tp); + +`tuple_apply(f, tp)` returns `std::forward(f)(std::get(std::forward(tp))...)` for `J` in 0..`N-1`, +where `N` is `std::tuple_size::type>::value`. Same as `std::apply` in C++17. + ## tuple_for_each(tp, f) template constexpr F tuple_for_each(Tp&& tp, F&& f); diff --git a/include/boost/mp11/tuple.hpp b/include/boost/mp11/tuple.hpp index 8ac99cc..754295c 100644 --- a/include/boost/mp11/tuple.hpp +++ b/include/boost/mp11/tuple.hpp @@ -21,6 +21,26 @@ namespace boost namespace mp11 { +// tuple_apply +namespace detail +{ + +template BOOST_CONSTEXPR auto tuple_apply_impl( F && f, Tp && tp, integer_sequence ) + -> decltype( std::forward(f)( std::get(std::forward(tp))... ) ) +{ + return std::forward(f)( std::get(std::forward(tp))... ); +} + +} // namespace detail + +template::type>::value>> +BOOST_CONSTEXPR auto tuple_apply( F && f, Tp && tp ) + -> decltype( detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ) ) +{ + return detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ); +} + // tuple_for_each namespace detail { diff --git a/include/boost/mp11_single.hpp b/include/boost/mp11_single.hpp index af97b45..c4086e2 100644 --- a/include/boost/mp11_single.hpp +++ b/include/boost/mp11_single.hpp @@ -2675,6 +2675,26 @@ namespace boost namespace mp11 { +// tuple_apply +namespace detail +{ + +template BOOST_CONSTEXPR auto tuple_apply_impl( F && f, Tp && tp, integer_sequence ) + -> decltype( std::forward(f)( std::get(std::forward(tp))... ) ) +{ + return std::forward(f)( std::get(std::forward(tp))... ); +} + +} // namespace detail + +template::type>::value>> +BOOST_CONSTEXPR auto tuple_apply( F && f, Tp && tp ) + -> decltype( detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ) ) +{ + return detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ); +} + // tuple_for_each namespace detail { diff --git a/test/Jamfile b/test/Jamfile index 1521645..02cd885 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -93,9 +93,11 @@ run mp_invoke_sf.cpp : : : $(REQ) ; # integer_sequence run integer_sequence.cpp : : : $(REQ) ; -# tuple_for_each +# tuple run tuple_for_each.cpp : : : $(REQ) ; run tuple_for_each_cx.cpp : : : $(REQ) ; +run tuple_apply.cpp : : : $(REQ) ; +run tuple_apply_cx.cpp : : : $(REQ) ; # set run mp_set_contains.cpp : : : $(REQ) ; diff --git a/test/tuple_apply.cpp b/test/tuple_apply.cpp new file mode 100644 index 0000000..e178dc8 --- /dev/null +++ b/test/tuple_apply.cpp @@ -0,0 +1,132 @@ + +// Copyright 2015, 2017 Peter Dimov. +// +// 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 +#include +#include +#include +#include +#include + +int main() +{ + using boost::mp11::tuple_apply; + + { + std::tuple tp{ 1, 2, 3 }; + + { + int s = tuple_apply( [&]( int x, int y, int z ){ return 100 * x + 10 * y + z; }, tp ); + BOOST_TEST_EQ( s, 123 ); + } + + { + int s = tuple_apply( [&]( int x, int y, int z ){ return 100 * x + 10 * y + z; }, std::move(tp) ); + BOOST_TEST_EQ( s, 123 ); + } + } + + { + std::tuple const tp{ 1, 2, 3 }; + + { + int s = tuple_apply( [&]( int x, int y, int z ){ return 100 * x + 10 * y + z; }, tp ); + BOOST_TEST_EQ( s, 123 ); + } + + { + int s = tuple_apply( [&]( int x, int y, int z ){ return 100 * x + 10 * y + z; }, std::move(tp) ); + BOOST_TEST_EQ( s, 123 ); + } + } + +#if defined( __clang_major__ ) && __clang_major__ == 3 && __clang_minor__ < 8 +#else + + { + std::tuple, std::unique_ptr, std::unique_ptr> tp{ std::unique_ptr(new int(1)), std::unique_ptr(new int(2)), std::unique_ptr(new int(3)) }; + + int s = tuple_apply( [&]( std::unique_ptr px, std::unique_ptr py, std::unique_ptr pz ){ return 100 * *px + 10 * *py + *pz; }, std::move(tp) ); + BOOST_TEST_EQ( s, 123 ); + } + +#endif + + { + std::pair tp{ 1, 2 }; + + { + int s = tuple_apply( [&]( int x, int y ){ return 10 * x + y; }, tp ); + BOOST_TEST_EQ( s, 12 ); + } + + { + int s = tuple_apply( [&]( int x, int y ){ return 10 * x + y; }, std::move(tp) ); + BOOST_TEST_EQ( s, 12 ); + } + } + + { + std::pair const tp{ 1, 2 }; + + { + int s = tuple_apply( [&]( int x, int y ){ return 10 * x + y; }, tp ); + BOOST_TEST_EQ( s, 12 ); + } + + { + int s = tuple_apply( [&]( int x, int y ){ return 10 * x + y; }, std::move(tp) ); + BOOST_TEST_EQ( s, 12 ); + } + } + + { + std::array tp{{ 1, 2, 3 }}; + + { + int s = tuple_apply( [&]( int x, int y, int z ){ return 100 * x + 10 * y + z; }, tp ); + BOOST_TEST_EQ( s, 123 ); + } + + { + int s = tuple_apply( [&]( int x, int y, int z ){ return 100 * x + 10 * y + z; }, std::move(tp) ); + BOOST_TEST_EQ( s, 123 ); + } + } + + { + std::array const tp{{ 1, 2, 3 }}; + + { + int s = tuple_apply( [&]( int x, int y, int z ){ return 100 * x + 10 * y + z; }, tp ); + BOOST_TEST_EQ( s, 123 ); + } + + { + int s = tuple_apply( [&]( int x, int y, int z ){ return 100 * x + 10 * y + z; }, std::move(tp) ); + BOOST_TEST_EQ( s, 123 ); + } + } + + { + std::tuple<> tp; + + BOOST_TEST_EQ( tuple_apply( []{ return 11; }, tp ), 11 ); + BOOST_TEST_EQ( tuple_apply( []{ return 12; }, std::move( tp ) ), 12 ); + } + + { + std::array tp; + + BOOST_TEST_EQ( tuple_apply( []{ return 11; }, tp ), 11 ); + BOOST_TEST_EQ( tuple_apply( []{ return 12; }, std::move( tp ) ), 12 ); + } + + return boost::report_errors(); +} diff --git a/test/tuple_apply_cx.cpp b/test/tuple_apply_cx.cpp new file mode 100644 index 0000000..785d5a8 --- /dev/null +++ b/test/tuple_apply_cx.cpp @@ -0,0 +1,66 @@ + +// Copyright 2015 Peter Dimov. +// +// 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 +#include + +// Technically std::tuple isn't constexpr enabled in C++11, but it works with libstdc++ + +#if defined( BOOST_NO_CXX11_CONSTEXPR ) || ( defined( _LIBCPP_VERSION ) && __cplusplus < 201400L ) + +int main() {} + +#else + +#include +#include +#include + +constexpr int f( int x, int y, int z ) +{ + return x * 100 + y * 10 + z; +} + +constexpr int g( int x, int y ) +{ + return x * 10 + y; +} + +constexpr int h() +{ + return 11; +} + +int main() +{ + { + constexpr std::tuple tp{ 1, 2, 3 }; + constexpr auto r = boost::mp11::tuple_apply( f, tp ); + static_assert( r == 123, "r == 123" ); + } + + { + constexpr std::pair tp{ 1, 2 }; + constexpr auto r = boost::mp11::tuple_apply( g, tp ); + static_assert( r == 12, "r == 12" ); + } + + { + constexpr std::array tp{{ 1, 2, 3 }}; + constexpr auto r = boost::mp11::tuple_apply( f, tp ); + static_assert( r == 123, "r == 123" ); + } + + { + constexpr std::tuple<> tp; + constexpr auto r = boost::mp11::tuple_apply( h, tp ); + static_assert( r == 11, "r == 11" ); + } +} + +#endif diff --git a/test/tuple_for_each.cpp b/test/tuple_for_each.cpp index 467d776..c16deb9 100644 --- a/test/tuple_for_each.cpp +++ b/test/tuple_for_each.cpp @@ -38,6 +38,26 @@ int main() } } + { + std::tuple const tp{ 1, 2, 3 }; + + { + int s = 0; + + tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); + + BOOST_TEST_EQ( s, 123 ); + } + + { + int s = 0; + + tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); + + BOOST_TEST_EQ( s, 123 ); + } + } + #if defined( __clang_major__ ) && __clang_major__ == 3 && __clang_minor__ < 8 #else @@ -73,6 +93,26 @@ int main() } } + { + std::pair const tp{ 1, 2 }; + + { + int s = 0; + + tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); + + BOOST_TEST_EQ( s, 12 ); + } + + { + int s = 0; + + tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); + + BOOST_TEST_EQ( s, 12 ); + } + } + { std::array tp{{ 1, 2, 3 }}; @@ -93,6 +133,26 @@ int main() } } + { + std::array const tp{{ 1, 2, 3 }}; + + { + int s = 0; + + tuple_for_each( tp, [&]( int x ){ s = s * 10 + x; } ); + + BOOST_TEST_EQ( s, 123 ); + } + + { + int s = 0; + + tuple_for_each( std::move(tp), [&]( int x ){ s = s * 10 + x; } ); + + BOOST_TEST_EQ( s, 123 ); + } + } + { std::tuple<> tp;