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..0fb5124 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -589,8 +589,10 @@ 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 +2809,32 @@ 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_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.

    +
    +
    +
    +

    construct_from_tuple<T>(tp)

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

    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.

    +
    +

    tuple_for_each(tp, f)

    @@ -2847,7 +2874,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.adoc b/doc/mp11/tuple.adoc new file mode 100644 index 0000000..46baab3 --- /dev/null +++ b/doc/mp11/tuple.adoc @@ -0,0 +1,38 @@ +//// +Copyright 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 +//// + +[#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. + +## construct_from_tuple(tp) + + template T construct_from_tuple(Tp&& tp); + +`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) + + template constexpr F tuple_for_each(Tp&& tp, F&& f); + +`tuple_for_each(tp, f)` applies the function object `f` to each element of `tp` by evaluating the +expression `f(std::get(std::forward(tp)))` for `J` in 0..`N-1`, where `N` is `std::tuple_size::type>::value`. + +Returns `std::forward(f)`. diff --git a/doc/mp11/tuple_for_each.adoc b/doc/mp11/tuple_for_each.adoc deleted file mode 100644 index 52afd04..0000000 --- a/doc/mp11/tuple_for_each.adoc +++ /dev/null @@ -1,21 +0,0 @@ -//// -Copyright 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 -//// - -[#tuple_for_each] -# A "for each" algorithm for tuple-like types, -:idprefix: - -## tuple_for_each(tp, f) - - template constexpr F tuple_for_each(Tp&& tp, F&& f); - -`tuple_for_each(tp, f)` applies the function object `f` to each element of `tp` by evaluating the -expression `f(std::get(std::forward(tp)))` for `J` in 0..`N-1`, where `N` is `std::tuple_size::type>::value`. - -Returns `std::forward(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.hpp b/include/boost/mp11/tuple.hpp new file mode 100644 index 0000000..afcd119 --- /dev/null +++ b/include/boost/mp11/tuple.hpp @@ -0,0 +1,92 @@ +#ifndef BOOST_MP11_TUPLE_HPP_INCLUDED +#define BOOST_MP11_TUPLE_HPP_INCLUDED + +// 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 + +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() ); +} + +// construct_from_tuple +namespace detail +{ + +template BOOST_CONSTEXPR T construct_from_tuple_impl( Tp && tp, integer_sequence ) +{ + return T( std::get(std::forward(tp))... ); +} + +} // namespace detail + +template::type>::value>> +BOOST_CONSTEXPR T construct_from_tuple( Tp && tp ) +{ + return detail::construct_from_tuple_impl( std::forward(tp), Seq() ); +} + +// tuple_for_each +namespace detail +{ + +template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence, F && f ) +{ + using A = int[sizeof...(J)]; + return (void)A{ ((void)f(std::get(std::forward(tp))), 0)... }, std::forward(f); +} + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1800 ) + +template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence, F && f ) +{ + return std::forward(f); +} + +#endif + +} // namespace detail + +template BOOST_CONSTEXPR F tuple_for_each( Tp && tp, F && f ) +{ + using seq = make_index_sequence::type>::value>; + return detail::tuple_for_each_impl( std::forward(tp), seq(), std::forward(f) ); +} + +} // namespace mp11 +} // namespace boost + +#endif // #ifndef BOOST_TUPLE_HPP_INCLUDED diff --git a/include/boost/mp11/tuple_for_each.hpp b/include/boost/mp11/tuple_for_each.hpp deleted file mode 100644 index a58098e..0000000 --- a/include/boost/mp11/tuple_for_each.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef BOOST_MP11_TUPLE_FOR_EACH_HPP_INCLUDED -#define BOOST_MP11_TUPLE_FOR_EACH_HPP_INCLUDED - -// 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 - -namespace boost -{ -namespace mp11 -{ - -namespace detail -{ - -template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence, F && f ) -{ - using A = int[sizeof...(J)]; - return (void)A{ ((void)f(std::get(std::forward(tp))), 0)... }, std::forward(f); -} - -#if BOOST_WORKAROUND( BOOST_MSVC, <= 1800 ) - -template BOOST_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence, F && f ) -{ - return std::forward(f); -} - -#endif - -} // namespace detail - -template BOOST_CONSTEXPR F tuple_for_each( Tp && tp, F && f ) -{ - using seq = make_index_sequence::type>::value>; - return detail::tuple_for_each_impl( std::forward(tp), seq(), std::forward(f) ); -} - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_TUPLE_FOR_EACH_HPP_INCLUDED diff --git a/include/boost/mp11_single.hpp b/include/boost/mp11_single.hpp index d11c020..7e658ab 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 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() ); +} + +// construct_from_tuple +namespace detail +{ + +template BOOST_CONSTEXPR T construct_from_tuple_impl( Tp && tp, integer_sequence ) +{ + return T( std::get(std::forward(tp))... ); +} + +} // namespace detail + +template::type>::value>> +BOOST_CONSTEXPR T construct_from_tuple( Tp && tp ) +{ + return detail::construct_from_tuple_impl( std::forward(tp), Seq() ); +} + +// tuple_for_each namespace detail { @@ -2704,6 +2743,6 @@ 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 #endif // #ifndef BOOST_MP11_HPP_INCLUDED diff --git a/test/Jamfile b/test/Jamfile index 1521645..a975fc3 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -93,9 +93,13 @@ 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) ; +compile tuple_for_each_cx.cpp : : : $(REQ) ; +run tuple_apply.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/construct_from_tuple.cpp b/test/construct_from_tuple.cpp new file mode 100644 index 0000000..d56bd3c --- /dev/null +++ b/test/construct_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::construct_from_tuple; + + { + std::tuple tp{ 1, 2, 3 }; + + { + T1 t1 = construct_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + + { + T1 t1 = construct_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 = construct_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + + { + T1 t1 = construct_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 = construct_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 = construct_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + + { + T1 t1 = construct_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 = construct_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + + { + T1 t1 = construct_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 = construct_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + + { + T1 t1 = construct_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 = construct_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 1 ); + BOOST_TEST_EQ( t1.y, 2 ); + BOOST_TEST_EQ( t1.z, 3 ); + } + + { + T1 t1 = construct_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 = construct_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 0 ); + BOOST_TEST_EQ( t1.y, 0 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + + { + T1 t1 = construct_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 = construct_from_tuple( tp ); + + BOOST_TEST_EQ( t1.x, 0 ); + BOOST_TEST_EQ( t1.y, 0 ); + BOOST_TEST_EQ( t1.z, 0 ); + } + + { + T1 t1 = construct_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/construct_from_tuple_cx.cpp b/test/construct_from_tuple_cx.cpp new file mode 100644 index 0000000..62ea3db --- /dev/null +++ b/test/construct_from_tuple_cx.cpp @@ -0,0 +1,82 @@ + +// 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::construct_from_tuple; + + { + constexpr std::tuple tp{ 1, 2, 3 }; + + constexpr auto r = construct_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 = construct_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 = construct_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" ); + } + +#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 = construct_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 +} + +#endif 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..2fce51b --- /dev/null +++ b/test/tuple_apply_cx.cpp @@ -0,0 +1,72 @@ + +// 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" ); + } + +#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.cpp b/test/tuple_for_each.cpp index 449fd15..c16deb9 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 @@ -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; diff --git a/test/tuple_for_each_cx.cpp b/test/tuple_for_each_cx.cpp index 730f6d2..f6960f6 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++ @@ -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 {