diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index fbd2628..bb44f3d 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -642,8 +642,13 @@ public: }); } - template constexpr variant( U&& u ) - noexcept( std::is_nothrow_constructible< variant2::detail::resolve_overload_type, U >::value ) + template, variant>::value>, + class V = variant2::detail::resolve_overload_type, + class E2 = std::enable_if_t::value> + > + constexpr variant( U&& u ) + noexcept( std::is_nothrow_constructible::value ) : variant_base( variant2::detail::resolve_overload_index(), std::forward(u) ) { } @@ -714,9 +719,9 @@ public: template, variant>::value>, class V = variant2::detail::resolve_overload_type, - class E2 = std::enable_if_t::value && std::is_constructible::value> + class E2 = std::enable_if_t::value && std::is_constructible::value> > - variant& operator=( U&& u ) // noexcept(see below ); + 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; @@ -733,7 +738,6 @@ public: } // modifiers - // using variant_base::emplace; template, U>> U& emplace( A&&... a ) { @@ -777,28 +781,30 @@ template constexpr bool operator==( variant const & v, variant { if( v.index() != w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) == get(w); + if( I == v.index() ) r = get(v) == get(w); }); - assert( false ); - return false; + return r; } template constexpr bool operator!=( variant const & v, variant const & w ) { if( v.index() != w.index() ) return true; + bool r = true; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) != get(w); + if( I == v.index() ) r = get(v) != get(w); }); - assert( false ); - return true; + return r; } template constexpr bool operator<( variant const & v, variant const & w ) @@ -806,14 +812,15 @@ template constexpr bool operator<( variant const & v, variant< if( v.index() < w.index() ) return true; if( v.index() > w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) < get(w); + if( I == v.index() ) r = get(v) < get(w); }); - assert( false ); - return false; + return r; } template constexpr bool operator>( variant const & v, variant const & w ) @@ -821,14 +828,15 @@ template constexpr bool operator>( variant const & v, variant if( v.index() > w.index() ) return true; if( v.index() < w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) > get(w); + if( I == v.index() ) r = get(v) > get(w); }); - assert( false ); - return false; + return r; } template constexpr bool operator<=( variant const & v, variant const & w ) @@ -836,14 +844,15 @@ template constexpr bool operator<=( variant const & v, variant if( v.index() < w.index() ) return true; if( v.index() > w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) <= get(w); + if( I == v.index() ) r = get(v) <= get(w); }); - assert( false ); - return false; + return r; } template constexpr bool operator>=( variant const & v, variant const & w ) @@ -851,14 +860,15 @@ template constexpr bool operator>=( variant const & v, variant if( v.index() > w.index() ) return true; if( v.index() < w.index() ) return false; + bool r = false; + mp_for_each>([&]( auto I ){ - if( I == v.index() ) return get(v) >= get(w); + if( I == v.index() ) r = get(v) >= get(w); }); - assert( false ); - return false; + return r; } // visitation diff --git a/test/Jamfile b/test/Jamfile index 5996a29..8ce5517 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -21,3 +21,5 @@ run get_by_type.cpp : : : $(REQ) ; compile get_by_type_cx.cpp : : : $(REQ) ; run variant_default_construct.cpp : : : $(REQ) ; compile variant_default_construct_cx.cpp : : : $(REQ) ; +run variant_copy_construct.cpp : : : $(REQ) ; +run variant_move_construct.cpp : : : $(REQ) ; diff --git a/test/variant_copy_construct.cpp b/test/variant_copy_construct.cpp new file mode 100644 index 0000000..bf060f8 --- /dev/null +++ b/test/variant_copy_construct.cpp @@ -0,0 +1,120 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + X1() {} + X1(X1 const&) {} + X1(X1&&) {} +}; + +inline bool operator==( X1, X1 ) { return true; } + +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 X2 +{ + X2() {} + X2(X2 const&) {} + X2(X2&&) {} +}; + +inline bool operator==( X2, X2 ) { return true; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); + +template static void test( V const & v ) +{ + V v2( v ); + + BOOST_TEST_EQ( v.index(), v2.index() ); + BOOST_TEST( v == v2 ); +} + +int main() +{ + test( variant() ); + test( variant(1) ); + + test( variant() ); + test( variant(1) ); + + test( variant() ); + test( variant(1) ); + test( variant(3.14f) ); + + test( variant() ); + test( variant(1) ); + test( variant(3.14f) ); + test( variant("test") ); + + test( variant() ); + + test( variant() ); + test( variant(3.14f) ); + + test( variant() ); + + test( variant("test") ); + + test( variant() ); + + test( variant() ); + test( variant() ); + test( variant() ); + test( variant() ); + + { + variant v; + v.emplace(); + + test( v ); + } + + { + variant v; + v.emplace(); + + test( v ); + } + + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible>)); + } + + return boost::report_errors(); +} diff --git a/test/variant_move_construct.cpp b/test/variant_move_construct.cpp new file mode 100644 index 0000000..bee71e6 --- /dev/null +++ b/test/variant_move_construct.cpp @@ -0,0 +1,121 @@ + +// 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 + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ + X1() {} + X1(X1 const&) {} + X1(X1&&) {} +}; + +inline bool operator==( X1, X1 ) { return true; } + +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 X2 +{ + X2() {} + X2(X2 const&) {} + X2(X2&&) {} +}; + +inline bool operator==( X2, X2 ) { return true; } + +STATIC_ASSERT( !std::is_nothrow_default_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_copy_constructible::value ); +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); + +template static void test( V&& v ) +{ + V v2( v ); + V v3( std::move(v) ); + + BOOST_TEST_EQ( v2.index(), v3.index() ); + BOOST_TEST( v2 == v3 ); +} + +int main() +{ + test( variant() ); + test( variant(1) ); + + test( variant() ); + test( variant(1) ); + + test( variant() ); + test( variant(1) ); + test( variant(3.14f) ); + + test( variant() ); + test( variant(1) ); + test( variant(3.14f) ); + test( variant("test") ); + + test( variant() ); + + test( variant() ); + test( variant(3.14f) ); + + test( variant() ); + + test( variant("test") ); + + test( variant() ); + + test( variant() ); + test( variant() ); + test( variant() ); + test( variant() ); + + { + variant v; + v.emplace(); + + test( std::move(v) ); + } + + { + variant v; + v.emplace(); + + test( std::move(v) ); + } + + { + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_TRUE((std::is_nothrow_move_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible>)); + } + + return boost::report_errors(); +}