From 7d25e131bebe77ad9915bbeeb209a35f69ab8de3 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 31 May 2017 07:42:45 +0300 Subject: [PATCH] Add SFINAE conditions --- include/boost/variant2/variant.hpp | 60 +++++++++++++++++++----------- test/variant_copy_assign.cpp | 26 +++++++++++++ test/variant_copy_construct.cpp | 8 ++++ test/variant_default_construct.cpp | 8 ++++ test/variant_move_assign.cpp | 26 +++++++++++++ test/variant_move_construct.cpp | 8 ++++ 6 files changed, 115 insertions(+), 21 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 145df70..b79f1fe 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -118,7 +118,7 @@ template constexpr variant_alternative_t() ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); #else @@ -134,7 +134,7 @@ template constexpr variant_alternative_t() ) ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); #else @@ -150,7 +150,7 @@ template constexpr variant_alternative_t() ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); #else @@ -166,7 +166,7 @@ template constexpr variant_alternative_t() ) ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); #else @@ -185,7 +185,7 @@ template constexpr U& get(variant& v) #if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) - return (void)( v.index() != I? throw bad_variant_access(): 0), v._get_impl( mp_size_t() ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); #else @@ -202,7 +202,7 @@ template constexpr U&& get(variant&& v) #if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) - return (void)( v.index() != I? throw bad_variant_access(): 0), std::move( v._get_impl( mp_size_t() ) ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); #else @@ -219,7 +219,7 @@ template constexpr U const& get(variant const& v) #if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) - return (void)( v.index() != I? throw bad_variant_access(): 0), v._get_impl( mp_size_t() ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp_size_t() ); #else @@ -236,7 +236,7 @@ template constexpr U const&& get(variant const&& v) #if BOOST_WORKAROUND( BOOST_GCC, < 60000 ) - return (void)( v.index() != I? throw bad_variant_access(): 0), std::move( v._get_impl( mp_size_t() ) ); + return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp_size_t() ) ); #else @@ -392,7 +392,7 @@ template using resolve_overload_index = mp_find struct variant_base_impl; // trivially destructible, single buffered -template using variant_base = variant_base_impl...>::value, mp_all...>::value || mp_any...>::value, T...>; +template using variant_base = variant_base_impl...>::value, mp_any...>, std::is_nothrow_default_constructible...>::value, T...>; struct none {}; @@ -790,16 +790,23 @@ private: using variant_base = variant2::detail::variant_base; +private: + + variant( variant const volatile& r ) = delete; + variant& operator=( variant const volatile& r ) = delete; + public: // constructors + template> >, E1>> constexpr variant() noexcept( std::is_nothrow_default_constructible< mp_first> >::value ) : variant_base( mp_size_t<0>() ) { } + template...>, E1>> variant( variant const& r ) noexcept( mp_all...>::value ) { @@ -813,6 +820,7 @@ public: }); } + template...>, E1>> variant( variant && r ) noexcept( mp_all...>::value ) { @@ -838,28 +846,30 @@ public: { } - template, U>> + template, U>, class E = std::enable_if_t::value>> constexpr explicit variant( in_place_type_t, A&&... a ): variant_base( I(), std::forward(a)... ) { } - template, U>> + template, U>, class E = std::enable_if_t&, A...>::value>> constexpr explicit variant( in_place_type_t, std::initializer_list il, A&&... a ): variant_base( I(), il, std::forward(a)... ) { } - template + template, I>, A...>::value>> constexpr explicit variant( in_place_index_t, A&&... a ): variant_base( mp_size_t(), std::forward(a)... ) { } - template + template, I>, std::initializer_list&, A...>::value>> constexpr explicit variant( in_place_index_t, std::initializer_list il, A&&... a ): variant_base( mp_size_t(), il, std::forward(a)... ) { } // assignment + template..., std::is_copy_assignable...>, E1>> variant& operator=( variant const & r ) + noexcept( mp_all..., std::is_nothrow_copy_assignable...>::value ) { mp_for_each>([&]( auto I ){ @@ -882,7 +892,9 @@ public: return *this; } - variant& operator=( variant&& r ) noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) + template..., std::is_move_assignable...>, E1>> + variant& operator=( variant && r ) + noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) { mp_for_each>([&]( auto I ){ @@ -909,8 +921,9 @@ public: class E1 = std::enable_if_t, variant>::value>, class V = variant2::detail::resolve_overload_type, class E2 = std::enable_if_t::value && std::is_constructible::value> - > - variant& operator=( U&& u ) noexcept( std::is_nothrow_assignable::value && std::is_nothrow_constructible::value ) + > + variant& operator=( U&& u ) + noexcept( std::is_nothrow_assignable::value && std::is_nothrow_constructible::value ) { std::size_t const I = variant2::detail::resolve_overload_index::value; @@ -928,25 +941,29 @@ public: // modifiers - template, U>> U& emplace( A&&... a ) + template, U>, class E = std::enable_if_t::value>> + U& emplace( A&&... a ) { variant_base::template emplace( std::forward(a)... ); return _get_impl( I() ); } - template, U>> U& emplace( std::initializer_list il, A&&... a ) + template, U>, class E = std::enable_if_t&, A...>::value>> + U& emplace( std::initializer_list il, A&&... a ) { variant_base::template emplace( il, std::forward(a)... ); return _get_impl( I() ); } - template variant_alternative_t>& emplace( A&&... a ) + template, I>, A...>::value>> + variant_alternative_t>& emplace( A&&... a ) { variant_base::template emplace( std::forward(a)... ); return _get_impl( mp_size_t() ); } - template variant_alternative_t>& emplace( std::initializer_list il, A&&... a ) + template, I>, std::initializer_list&, A...>::value>> + variant_alternative_t>& emplace( std::initializer_list il, A&&... a ) { variant_base::template emplace( il, std::forward(a)... ); return _get_impl( mp_size_t() ); @@ -1094,7 +1111,8 @@ template constexpr bool operator>=( variant const & v, variant template constexpr void visit( Visitor&&, Variants&&... ); // specialized algorithms -template void swap( variant & v, variant & w ) noexcept( noexcept(v.swap(w)) ) +template..., variant2::detail::is_swappable...>::value>> +void swap( variant & v, variant & w ) noexcept( noexcept(v.swap(w)) ) { v.swap( w ); } diff --git a/test/variant_copy_assign.cpp b/test/variant_copy_assign.cpp index eec88c7..c4ae80f 100644 --- a/test/variant_copy_assign.cpp +++ b/test/variant_copy_assign.cpp @@ -57,6 +57,11 @@ STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); +struct Y +{ + Y& operator=( Y const& ) = delete; +}; + int main() { { @@ -164,5 +169,26 @@ int main() BOOST_TEST_EQ( get<0>(v).v, 4 ); } + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_assignable>)); + + BOOST_TEST_TRAIT_TRUE((std::is_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_copy_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_copy_assignable>)); + } + return boost::report_errors(); } diff --git a/test/variant_copy_construct.cpp b/test/variant_copy_construct.cpp index bf060f8..473d8a2 100644 --- a/test/variant_copy_construct.cpp +++ b/test/variant_copy_construct.cpp @@ -43,6 +43,11 @@ STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +struct Y +{ + Y( Y const& ) = delete; +}; + template static void test( V const & v ) { V v2( v ); @@ -114,6 +119,9 @@ int main() BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_copy_constructible>)); } return boost::report_errors(); diff --git a/test/variant_default_construct.cpp b/test/variant_default_construct.cpp index c766345..894934c 100644 --- a/test/variant_default_construct.cpp +++ b/test/variant_default_construct.cpp @@ -20,6 +20,11 @@ struct X X(); }; +struct Y +{ + Y() = delete; +}; + int main() { { @@ -89,6 +94,9 @@ int main() BOOST_TEST_TRAIT_FALSE((std::is_nothrow_default_constructible>)); BOOST_TEST_TRAIT_FALSE((std::is_nothrow_default_constructible>)); BOOST_TEST_TRAIT_FALSE((std::is_nothrow_default_constructible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_default_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_default_constructible>)); } return boost::report_errors(); diff --git a/test/variant_move_assign.cpp b/test/variant_move_assign.cpp index 044428c..9c87718 100644 --- a/test/variant_move_assign.cpp +++ b/test/variant_move_assign.cpp @@ -57,6 +57,11 @@ STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); STATIC_ASSERT( !std::is_nothrow_copy_assignable::value ); STATIC_ASSERT( !std::is_nothrow_move_assignable::value ); +struct Y +{ + Y& operator=( Y&& ) = delete; +}; + int main() { { @@ -164,5 +169,26 @@ int main() BOOST_TEST_EQ( get<0>(v).v, 4 ); } + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_assignable>)); + + BOOST_TEST_TRAIT_TRUE((std::is_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_move_assignable>)); + BOOST_TEST_TRAIT_FALSE((std::is_move_assignable>)); + } + return boost::report_errors(); } diff --git a/test/variant_move_construct.cpp b/test/variant_move_construct.cpp index bee71e6..e3d8e98 100644 --- a/test/variant_move_construct.cpp +++ b/test/variant_move_construct.cpp @@ -43,6 +43,11 @@ STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +struct Y +{ + Y( Y&& ) = delete; +}; + template static void test( V&& v ) { V v2( v ); @@ -115,6 +120,9 @@ int main() BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_move_constructible>)); } return boost::report_errors();