From 08777edbc18e5a57d387392deeac07671dea06a8 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 8 Jun 2017 17:42:50 +0300 Subject: [PATCH] Add make_from_tuple --- doc/html/mp11.html | 13 ++ doc/mp11/tuple.adoc | 7 ++ include/boost/mp11/tuple.hpp | 18 +++ include/boost/mp11_single.hpp | 18 +++ test/Jamfile | 2 + test/make_from_tuple.cpp | 219 ++++++++++++++++++++++++++++++++++ test/make_from_tuple_cx.cpp | 76 ++++++++++++ 7 files changed, 353 insertions(+) create mode 100644 test/make_from_tuple.cpp create mode 100644 test/make_from_tuple_cx.cpp diff --git a/doc/html/mp11.html b/doc/html/mp11.html index 12d2697..3454142 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -592,6 +592,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • Tuple Operations, <boost/mp11/tuple.hpp>
  • @@ -2822,6 +2823,18 @@ where N is std::tuple_size<typename std::remove_reference&
    +

    make_from_tuple<T>(tp)

    +
    +
    +
    template<class T, class Tp> T make_from_tuple(Tp&& tp);
    +
    +
    +
    +

    make_from_tuple<T>(tp) returns T(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::make_from_tuple in C++17.

    +
    +
    +

    tuple_for_each(tp, f)

    diff --git a/doc/mp11/tuple.adoc b/doc/mp11/tuple.adoc index b9dd82c..2dc9f99 100644 --- a/doc/mp11/tuple.adoc +++ b/doc/mp11/tuple.adoc @@ -20,6 +20,13 @@ http://www.boost.org/LICENSE_1_0.txt `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. +## make_from_tuple(tp) + + template T make_from_tuple(Tp&& tp); + +`make_from_tuple(tp)` returns `T(std::get(std::forward(tp))...)` for `J` in 0..`N-1`, +where `N` is `std::tuple_size::type>::value`. Same as `std::make_from_tuple` 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 754295c..db8ce05 100644 --- a/include/boost/mp11/tuple.hpp +++ b/include/boost/mp11/tuple.hpp @@ -41,6 +41,24 @@ BOOST_CONSTEXPR auto tuple_apply( F && f, Tp && tp ) return detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ); } +// make_from_tuple +namespace detail +{ + +template BOOST_CONSTEXPR T make_from_tuple_impl( Tp && tp, integer_sequence ) +{ + return T( std::get(std::forward(tp))... ); +} + +} // namespace detail + +template::type>::value>> +BOOST_CONSTEXPR T make_from_tuple( Tp && tp ) +{ + return detail::make_from_tuple_impl( std::forward(tp), Seq() ); +} + // tuple_for_each namespace detail { diff --git a/include/boost/mp11_single.hpp b/include/boost/mp11_single.hpp index c4086e2..b45c39f 100644 --- a/include/boost/mp11_single.hpp +++ b/include/boost/mp11_single.hpp @@ -2695,6 +2695,24 @@ BOOST_CONSTEXPR auto tuple_apply( F && f, Tp && tp ) return detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ); } +// make_from_tuple +namespace detail +{ + +template BOOST_CONSTEXPR T make_from_tuple_impl( Tp && tp, integer_sequence ) +{ + return T( std::get(std::forward(tp))... ); +} + +} // namespace detail + +template::type>::value>> +BOOST_CONSTEXPR T make_from_tuple( Tp && tp ) +{ + return detail::make_from_tuple_impl( std::forward(tp), Seq() ); +} + // tuple_for_each namespace detail { diff --git a/test/Jamfile b/test/Jamfile index 02cd885..fbad85d 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -98,6 +98,8 @@ run tuple_for_each.cpp : : : $(REQ) ; run tuple_for_each_cx.cpp : : : $(REQ) ; run tuple_apply.cpp : : : $(REQ) ; run tuple_apply_cx.cpp : : : $(REQ) ; +run make_from_tuple.cpp : : : $(REQ) ; +run make_from_tuple_cx.cpp : : : $(REQ) ; # set run mp_set_contains.cpp : : : $(REQ) ; diff --git a/test/make_from_tuple.cpp b/test/make_from_tuple.cpp new file mode 100644 index 0000000..491a4a7 --- /dev/null +++ b/test/make_from_tuple.cpp @@ -0,0 +1,219 @@ + +// 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 +#include +#include + +struct T1 +{ + int x, y, z; + + T1( int x = 0, int y = 0, int z = 0 ): x(x), y(y), z(z) {} +}; + +struct T2 +{ + std::unique_ptr x, y, z; + + T2( std::unique_ptr x, std::unique_ptr y, std::unique_ptr z ): x(std::move(x)), y(std::move(y)), z(std::move(z)) {} + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1800 ) + + T2( T2&& r ): x( std::move(r.x) ), y( std::move(r.y) ), z( std::move(r.z) ) {} + +#endif +}; + +int main() +{ + using boost::mp11::make_from_tuple; + + { + std::tuple tp{ 1, 2, 3 }; + + { + T1 t1 = make_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + + { + T1 t1 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + } + + { + std::tuple const tp{ 1, 2, 3 }; + + { + T1 t1 = make_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + + { + T1 t1 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + } + +#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)) }; + + T2 t2 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( *t2.x, 1 ); + BOOST_TEST_EQ( *t2.y, 2 ); + BOOST_TEST_EQ( *t2.z, 3 ); + } + +#endif + + { + std::pair tp{ 1, 2 }; + + { + T1 t1 = make_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + + { + T1 t1 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + } + + { + std::pair const tp{ 1, 2 }; + + { + T1 t1 = make_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + + { + T1 t1 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + } + + { + std::array tp{{ 1, 2, 3 }}; + + { + T1 t1 = make_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + + { + T1 t1 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + } + + { + std::array const tp{{ 1, 2, 3 }}; + + { + T1 t1 = make_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + + { + T1 t1 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + } + + { + std::tuple<> tp; + + { + T1 t1 = make_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 0 ); + BOOST_TEST_EQ( t1.y, 0 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + + { + T1 t1 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( t1.x, 0 ); + BOOST_TEST_EQ( t1.y, 0 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + } + + { + std::array tp; + + { + T1 t1 = make_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 0 ); + BOOST_TEST_EQ( t1.y, 0 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + + { + T1 t1 = make_from_tuple( std::move(tp) ); + + BOOST_TEST_EQ( t1.x, 0 ); + BOOST_TEST_EQ( t1.y, 0 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + } + + return boost::report_errors(); +} diff --git a/test/make_from_tuple_cx.cpp b/test/make_from_tuple_cx.cpp new file mode 100644 index 0000000..7f2f1ab --- /dev/null +++ b/test/make_from_tuple_cx.cpp @@ -0,0 +1,76 @@ + +// 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 + +struct T1 +{ + int x, y, z; + + constexpr T1( int x = 0, int y = 0, int z = 0 ): x(x), y(y), z(z) {} +}; + +int main() +{ + using boost::mp11::make_from_tuple; + + { + constexpr std::tuple tp{ 1, 2, 3 }; + + constexpr auto r = make_from_tuple( tp ); + + static_assert( r.x == 1, "r.x == 1" ); + static_assert( r.y == 2, "r.y == 2" ); + static_assert( r.z == 3, "r.z == 3" ); + } + + { + constexpr std::pair tp{ 1, 2 }; + + constexpr auto r = make_from_tuple( tp ); + + static_assert( r.x == 1, "r.x == 1" ); + static_assert( r.y == 2, "r.y == 2" ); + static_assert( r.z == 0, "r.z == 0" ); + } + + { + constexpr std::array tp{{ 1, 2, 3 }}; + + constexpr auto r = make_from_tuple( tp ); + + static_assert( r.x == 1, "r.x == 1" ); + static_assert( r.y == 2, "r.y == 2" ); + static_assert( r.z == 3, "r.z == 3" ); + } + + { + constexpr std::tuple<> tp; + + constexpr auto r = make_from_tuple( tp ); + + static_assert( r.x == 0, "r.x == 0" ); + static_assert( r.y == 0, "r.y == 0" ); + static_assert( r.z == 0, "r.z == 0" ); + } +} + +#endif