From 97720ed72d9d628ee906e718843e1adc3dfb0b92 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 8 Jun 2017 16:35:55 +0300 Subject: [PATCH 1/5] Rename tuple_for_each.hpp to tuple.hpp --- README.md | 2 +- doc/html/mp11.html | 6 +++--- doc/mp11/reference.adoc | 2 +- doc/mp11/{tuple_for_each.adoc => tuple.adoc} | 4 ++-- include/boost/mp11.hpp | 2 +- include/boost/mp11/{tuple_for_each.hpp => tuple.hpp} | 7 ++++--- include/boost/mp11_single.hpp | 7 ++++--- test/tuple_for_each.cpp | 2 +- test/tuple_for_each_cx.cpp | 2 +- 9 files changed, 18 insertions(+), 16 deletions(-) rename doc/mp11/{tuple_for_each.adoc => tuple.adoc} (85%) rename include/boost/mp11/{tuple_for_each.hpp => tuple.hpp} (89%) diff --git a/README.md b/README.md index 05119f5..5861ed5 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Tested on [Travis](https://travis-ci.org/pdimov/mp11/) and [Appveyor](https://ci * [Integer Sequences](doc/mp11/integer_sequence.adoc) -* [A "for each" algorithm for tuple-like types](doc/mp11/tuple_for_each.adoc) +* [Tuple Operations](doc/mp11/tuple.adoc) ## License diff --git a/doc/html/mp11.html b/doc/html/mp11.html index 2a9c058..2b30e0e 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -589,7 +589,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • index_sequence_for<T…​>
  • -
  • A "for each" algorithm for tuple-like types, <boost/mp11/tuple_for_each.hpp> +
  • Tuple Operations, <boost/mp11/tuple.hpp> @@ -2807,7 +2807,7 @@ of U…​ and the mp_bind expressions replace
    -

    A "for each" algorithm for tuple-like types, <boost/mp11/tuple_for_each.hpp>

    +

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

    tuple_for_each(tp, f)

    @@ -2847,7 +2847,7 @@ expression f(std::get<J>(std::forward<Tp>(tp))) for diff --git a/doc/mp11/reference.adoc b/doc/mp11/reference.adoc index 113b0bd..208c9b3 100644 --- a/doc/mp11/reference.adoc +++ b/doc/mp11/reference.adoc @@ -35,6 +35,6 @@ include::bind.adoc[] include::integer_sequence.adoc[] -include::tuple_for_each.adoc[] +include::tuple.adoc[] :leveloffset: -1 diff --git a/doc/mp11/tuple_for_each.adoc b/doc/mp11/tuple.adoc similarity index 85% rename from doc/mp11/tuple_for_each.adoc rename to doc/mp11/tuple.adoc index 52afd04..53b8c19 100644 --- a/doc/mp11/tuple_for_each.adoc +++ b/doc/mp11/tuple.adoc @@ -7,8 +7,8 @@ See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt //// -[#tuple_for_each] -# A "for each" algorithm for tuple-like types, +[#tuple] +# Tuple Operations, :idprefix: ## tuple_for_each(tp, f) diff --git a/include/boost/mp11.hpp b/include/boost/mp11.hpp index 05a51ca..5e45939 100644 --- a/include/boost/mp11.hpp +++ b/include/boost/mp11.hpp @@ -17,6 +17,6 @@ #include #include #include -#include +#include #endif // #ifndef BOOST_MP11_HPP_INCLUDED diff --git a/include/boost/mp11/tuple_for_each.hpp b/include/boost/mp11/tuple.hpp similarity index 89% rename from include/boost/mp11/tuple_for_each.hpp rename to include/boost/mp11/tuple.hpp index a58098e..8ac99cc 100644 --- a/include/boost/mp11/tuple_for_each.hpp +++ b/include/boost/mp11/tuple.hpp @@ -1,5 +1,5 @@ -#ifndef BOOST_MP11_TUPLE_FOR_EACH_HPP_INCLUDED -#define BOOST_MP11_TUPLE_FOR_EACH_HPP_INCLUDED +#ifndef BOOST_MP11_TUPLE_HPP_INCLUDED +#define BOOST_MP11_TUPLE_HPP_INCLUDED // Copyright 2015, 2017 Peter Dimov. // @@ -21,6 +21,7 @@ namespace boost namespace mp11 { +// tuple_for_each namespace detail { @@ -50,4 +51,4 @@ template BOOST_CONSTEXPR F tuple_for_each( Tp && tp, F && f ) } // namespace mp11 } // namespace boost -#endif // #ifndef BOOST_TUPLE_FOR_EACH_HPP_INCLUDED +#endif // #ifndef BOOST_TUPLE_HPP_INCLUDED diff --git a/include/boost/mp11_single.hpp b/include/boost/mp11_single.hpp index d11c020..af97b45 100644 --- a/include/boost/mp11_single.hpp +++ b/include/boost/mp11_single.hpp @@ -2653,8 +2653,8 @@ template using mp_bind_back_q = mp_bind_back BOOST_CONSTEXPR F tuple_for_each( Tp && tp, F && f ) } // namespace mp11 } // namespace boost -#endif // #ifndef BOOST_TUPLE_FOR_EACH_HPP_INCLUDED +#endif // #ifndef BOOST_TUPLE_HPP_INCLUDED #endif // #ifndef BOOST_MP11_HPP_INCLUDED diff --git a/test/tuple_for_each.cpp b/test/tuple_for_each.cpp index 449fd15..467d776 100644 --- a/test/tuple_for_each.cpp +++ b/test/tuple_for_each.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt -#include +#include #include #include #include diff --git a/test/tuple_for_each_cx.cpp b/test/tuple_for_each_cx.cpp index 730f6d2..55e8d15 100644 --- a/test/tuple_for_each_cx.cpp +++ b/test/tuple_for_each_cx.cpp @@ -6,7 +6,7 @@ // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt -#include +#include #include // Technically std::tuple isn't constexpr enabled in C++11, but it works with libstdc++ From 359ae25630b8281e03b2e5ad74a83b0a88805b83 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 8 Jun 2017 17:19:28 +0300 Subject: [PATCH 2/5] Add tuple_apply --- doc/html/mp11.html | 13 ++++ doc/mp11/tuple.adoc | 9 +++ include/boost/mp11/tuple.hpp | 20 ++++++ include/boost/mp11_single.hpp | 20 ++++++ test/Jamfile | 4 +- test/tuple_apply.cpp | 132 ++++++++++++++++++++++++++++++++++ test/tuple_apply_cx.cpp | 66 +++++++++++++++++ test/tuple_for_each.cpp | 60 ++++++++++++++++ 8 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 test/tuple_apply.cpp create mode 100644 test/tuple_apply_cx.cpp 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; From 08777edbc18e5a57d387392deeac07671dea06a8 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 8 Jun 2017 17:42:50 +0300 Subject: [PATCH 3/5] 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 From 19865f6145dfd6e694d02a06b9146fc82f9001de Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 8 Jun 2017 18:21:55 +0300 Subject: [PATCH 4/5] Fix clang < 3.9 failures --- test/make_from_tuple_cx.cpp | 6 ++++++ test/tuple_apply_cx.cpp | 6 ++++++ test/tuple_for_each_cx.cpp | 1 + 3 files changed, 13 insertions(+) diff --git a/test/make_from_tuple_cx.cpp b/test/make_from_tuple_cx.cpp index 7f2f1ab..70b7ff2 100644 --- a/test/make_from_tuple_cx.cpp +++ b/test/make_from_tuple_cx.cpp @@ -62,6 +62,10 @@ int main() static_assert( r.z == 3, "r.z == 3" ); } +#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; @@ -71,6 +75,8 @@ int main() static_assert( r.y == 0, "r.y == 0" ); static_assert( r.z == 0, "r.z == 0" ); } + +#endif } #endif diff --git a/test/tuple_apply_cx.cpp b/test/tuple_apply_cx.cpp index 785d5a8..2fce51b 100644 --- a/test/tuple_apply_cx.cpp +++ b/test/tuple_apply_cx.cpp @@ -56,11 +56,17 @@ int main() static_assert( r == 123, "r == 123" ); } +#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 auto r = boost::mp11::tuple_apply( h, tp ); static_assert( r == 11, "r == 11" ); } + +#endif } #endif diff --git a/test/tuple_for_each_cx.cpp b/test/tuple_for_each_cx.cpp index 55e8d15..f6960f6 100644 --- a/test/tuple_for_each_cx.cpp +++ b/test/tuple_for_each_cx.cpp @@ -38,6 +38,7 @@ int main() } #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 { From cae6f966dcfca5e1de250540ba12bc582bf7710c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 8 Jun 2017 19:22:53 +0300 Subject: [PATCH 5/5] Rename make_from_tuple to construct_from_tuple --- doc/html/mp11.html | 11 +++--- doc/mp11/tuple.adoc | 9 ++--- include/boost/mp11/tuple.hpp | 8 ++--- include/boost/mp11_single.hpp | 8 ++--- test/Jamfile | 8 ++--- ...rom_tuple.cpp => construct_from_tuple.cpp} | 36 +++++++++---------- ...ple_cx.cpp => construct_from_tuple_cx.cpp} | 10 +++--- 7 files changed, 46 insertions(+), 44 deletions(-) rename test/{make_from_tuple.cpp => construct_from_tuple.cpp} (79%) rename test/{make_from_tuple_cx.cpp => construct_from_tuple_cx.cpp} (85%) diff --git a/doc/html/mp11.html b/doc/html/mp11.html index 3454142..0fb5124 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -592,7 +592,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • Tuple Operations, <boost/mp11/tuple.hpp>
  • @@ -2823,15 +2823,16 @@ where N is std::tuple_size<typename std::remove_reference&
    -

    make_from_tuple<T>(tp)

    +

    construct_from_tuple<T>(tp)

    -
    template<class T, class Tp> T make_from_tuple(Tp&& tp);
    +
    template<class T, class Tp> T construct_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.

    +

    construct_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. +The name of the function doesn’t match the C++17 one to avoid ambiguities when both are visible or in unqualified calls.

    diff --git a/doc/mp11/tuple.adoc b/doc/mp11/tuple.adoc index 2dc9f99..46baab3 100644 --- a/doc/mp11/tuple.adoc +++ b/doc/mp11/tuple.adoc @@ -20,12 +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) +## construct_from_tuple(tp) - template T make_from_tuple(Tp&& tp); + template T construct_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. +`construct_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 {cpp}17. +The name of the function doesn't match the {cpp}17 one to avoid ambiguities when both are visible or in unqualified calls. ## tuple_for_each(tp, f) diff --git a/include/boost/mp11/tuple.hpp b/include/boost/mp11/tuple.hpp index db8ce05..afcd119 100644 --- a/include/boost/mp11/tuple.hpp +++ b/include/boost/mp11/tuple.hpp @@ -41,11 +41,11 @@ BOOST_CONSTEXPR auto tuple_apply( F && f, Tp && tp ) return detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ); } -// make_from_tuple +// construct_from_tuple namespace detail { -template BOOST_CONSTEXPR T make_from_tuple_impl( Tp && tp, integer_sequence ) +template BOOST_CONSTEXPR T construct_from_tuple_impl( Tp && tp, integer_sequence ) { return T( std::get(std::forward(tp))... ); } @@ -54,9 +54,9 @@ template BOOST_CONSTEXPR T make_from_tuple_ template::type>::value>> -BOOST_CONSTEXPR T make_from_tuple( Tp && tp ) +BOOST_CONSTEXPR T construct_from_tuple( Tp && tp ) { - return detail::make_from_tuple_impl( std::forward(tp), Seq() ); + return detail::construct_from_tuple_impl( std::forward(tp), Seq() ); } // tuple_for_each diff --git a/include/boost/mp11_single.hpp b/include/boost/mp11_single.hpp index b45c39f..7e658ab 100644 --- a/include/boost/mp11_single.hpp +++ b/include/boost/mp11_single.hpp @@ -2695,11 +2695,11 @@ BOOST_CONSTEXPR auto tuple_apply( F && f, Tp && tp ) return detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ); } -// make_from_tuple +// construct_from_tuple namespace detail { -template BOOST_CONSTEXPR T make_from_tuple_impl( Tp && tp, integer_sequence ) +template BOOST_CONSTEXPR T construct_from_tuple_impl( Tp && tp, integer_sequence ) { return T( std::get(std::forward(tp))... ); } @@ -2708,9 +2708,9 @@ template BOOST_CONSTEXPR T make_from_tuple_ template::type>::value>> -BOOST_CONSTEXPR T make_from_tuple( Tp && tp ) +BOOST_CONSTEXPR T construct_from_tuple( Tp && tp ) { - return detail::make_from_tuple_impl( std::forward(tp), Seq() ); + return detail::construct_from_tuple_impl( std::forward(tp), Seq() ); } // tuple_for_each diff --git a/test/Jamfile b/test/Jamfile index fbad85d..a975fc3 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -95,11 +95,11 @@ run integer_sequence.cpp : : : $(REQ) ; # tuple run tuple_for_each.cpp : : : $(REQ) ; -run tuple_for_each_cx.cpp : : : $(REQ) ; +compile 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) ; +compile tuple_apply_cx.cpp : : : $(REQ) ; +run construct_from_tuple.cpp : : : $(REQ) ; +compile construct_from_tuple_cx.cpp : : : $(REQ) ; # set run mp_set_contains.cpp : : : $(REQ) ; diff --git a/test/make_from_tuple.cpp b/test/construct_from_tuple.cpp similarity index 79% rename from test/make_from_tuple.cpp rename to test/construct_from_tuple.cpp index 491a4a7..d56bd3c 100644 --- a/test/make_from_tuple.cpp +++ b/test/construct_from_tuple.cpp @@ -38,13 +38,13 @@ struct T2 int main() { - using boost::mp11::make_from_tuple; + using boost::mp11::construct_from_tuple; { std::tuple tp{ 1, 2, 3 }; { - T1 t1 = make_from_tuple( tp ); + T1 t1 = construct_from_tuple( tp ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -52,7 +52,7 @@ int main() } { - T1 t1 = make_from_tuple( std::move(tp) ); + T1 t1 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -64,7 +64,7 @@ int main() std::tuple const tp{ 1, 2, 3 }; { - T1 t1 = make_from_tuple( tp ); + T1 t1 = construct_from_tuple( tp ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -72,7 +72,7 @@ int main() } { - T1 t1 = make_from_tuple( std::move(tp) ); + T1 t1 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -86,7 +86,7 @@ int main() { 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) ); + T2 t2 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( *t2.x, 1 ); BOOST_TEST_EQ( *t2.y, 2 ); @@ -99,7 +99,7 @@ int main() std::pair tp{ 1, 2 }; { - T1 t1 = make_from_tuple( tp ); + T1 t1 = construct_from_tuple( tp ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -107,7 +107,7 @@ int main() } { - T1 t1 = make_from_tuple( std::move(tp) ); + T1 t1 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -119,7 +119,7 @@ int main() std::pair const tp{ 1, 2 }; { - T1 t1 = make_from_tuple( tp ); + T1 t1 = construct_from_tuple( tp ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -127,7 +127,7 @@ int main() } { - T1 t1 = make_from_tuple( std::move(tp) ); + T1 t1 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -139,7 +139,7 @@ int main() std::array tp{{ 1, 2, 3 }}; { - T1 t1 = make_from_tuple( tp ); + T1 t1 = construct_from_tuple( tp ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -147,7 +147,7 @@ int main() } { - T1 t1 = make_from_tuple( std::move(tp) ); + T1 t1 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -159,7 +159,7 @@ int main() std::array const tp{{ 1, 2, 3 }}; { - T1 t1 = make_from_tuple( tp ); + T1 t1 = construct_from_tuple( tp ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -167,7 +167,7 @@ int main() } { - T1 t1 = make_from_tuple( std::move(tp) ); + T1 t1 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( t1.x, 1 ); BOOST_TEST_EQ( t1.y, 2 ); @@ -179,7 +179,7 @@ int main() std::tuple<> tp; { - T1 t1 = make_from_tuple( tp ); + T1 t1 = construct_from_tuple( tp ); BOOST_TEST_EQ( t1.x, 0 ); BOOST_TEST_EQ( t1.y, 0 ); @@ -187,7 +187,7 @@ int main() } { - T1 t1 = make_from_tuple( std::move(tp) ); + T1 t1 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( t1.x, 0 ); BOOST_TEST_EQ( t1.y, 0 ); @@ -199,7 +199,7 @@ int main() std::array tp; { - T1 t1 = make_from_tuple( tp ); + T1 t1 = construct_from_tuple( tp ); BOOST_TEST_EQ( t1.x, 0 ); BOOST_TEST_EQ( t1.y, 0 ); @@ -207,7 +207,7 @@ int main() } { - T1 t1 = make_from_tuple( std::move(tp) ); + T1 t1 = construct_from_tuple( std::move(tp) ); BOOST_TEST_EQ( t1.x, 0 ); BOOST_TEST_EQ( t1.y, 0 ); diff --git a/test/make_from_tuple_cx.cpp b/test/construct_from_tuple_cx.cpp similarity index 85% rename from test/make_from_tuple_cx.cpp rename to test/construct_from_tuple_cx.cpp index 70b7ff2..62ea3db 100644 --- a/test/make_from_tuple_cx.cpp +++ b/test/construct_from_tuple_cx.cpp @@ -30,12 +30,12 @@ struct T1 int main() { - using boost::mp11::make_from_tuple; + using boost::mp11::construct_from_tuple; { constexpr std::tuple tp{ 1, 2, 3 }; - constexpr auto r = make_from_tuple( tp ); + constexpr auto r = construct_from_tuple( tp ); static_assert( r.x == 1, "r.x == 1" ); static_assert( r.y == 2, "r.y == 2" ); @@ -45,7 +45,7 @@ int main() { constexpr std::pair tp{ 1, 2 }; - constexpr auto r = make_from_tuple( tp ); + constexpr auto r = construct_from_tuple( tp ); static_assert( r.x == 1, "r.x == 1" ); static_assert( r.y == 2, "r.y == 2" ); @@ -55,7 +55,7 @@ int main() { constexpr std::array tp{{ 1, 2, 3 }}; - constexpr auto r = make_from_tuple( tp ); + constexpr auto r = construct_from_tuple( tp ); static_assert( r.x == 1, "r.x == 1" ); static_assert( r.y == 2, "r.y == 2" ); @@ -69,7 +69,7 @@ int main() { constexpr std::tuple<> tp; - constexpr auto r = make_from_tuple( tp ); + constexpr auto r = construct_from_tuple( tp ); static_assert( r.x == 0, "r.x == 0" ); static_assert( r.y == 0, "r.y == 0" );