From 01b22a0ff0f0c68dee34989555fdf857bf1ef2ca Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 28 Apr 2014 16:51:49 +0200 Subject: [PATCH] Added tests for move conversion between optional and optional --- include/boost/optional/optional.hpp | 29 +++++++++++++++- test/optional_test_move.cpp | 54 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index a8ba5e6..bbbe3be 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -587,6 +587,20 @@ class optional_base : public optional_tag // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error // instead of choosing the wrong overload // +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Notice that 'Expr' will be optional or optional (but not optional_base<..>) + template + void construct ( Expr&& expr, optional_tag const* ) + { + if ( expr.is_initialized() ) + { + // An exception can be thrown here. + // It it happens, THIS will be left uninitialized. + new (m_storage.address()) internal_type(types::move(expr.get())) ; + m_initialized = true ; + } + } +#else // Notice that 'Expr' will be optional or optional (but not optional_base<..>) template void construct ( Expr const& expr, optional_tag const* ) @@ -600,6 +614,7 @@ class optional_base : public optional_tag } } #endif +#endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; } void assign_value ( argument_type val, is_reference_tag ) { construct(val); } @@ -814,7 +829,7 @@ class optional : public optional_detail::optional_base #endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES #endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) - // Assigns from another convertible optional (converts && deep-copies the rhs value) + // Copy-assigns from another convertible optional (converts && deep-copies the rhs value) // Requires a valid conversion from U to T. // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED template @@ -823,6 +838,18 @@ class optional : public optional_detail::optional_base this->assign(rhs); return *this ; } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Move-assigns from another convertible optional (converts && deep-moves the rhs value) + // Requires a valid conversion from U to T. + // Basic Guarantee: If T::T( U && ) throws, this is left UNINITIALIZED + template + optional& operator= ( optional && rhs ) + { + this->assign(boost::move(rhs)); + return *this ; + } +#endif // Assigns from another optional (deep-copies the rhs value) // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED diff --git a/test/optional_test_move.cpp b/test/optional_test_move.cpp index cad5866..a2d20c1 100644 --- a/test/optional_test_move.cpp +++ b/test/optional_test_move.cpp @@ -239,6 +239,8 @@ public: private: MoveOnly(MoveOnly const&); void operator=(MoveOnly const&); + + friend class MoveOnlyB; }; void test_with_move_only() @@ -262,6 +264,56 @@ void test_with_move_only() BOOST_CHECK(o4->val == 0); } +class MoveOnlyB +{ +public: + int val; + MoveOnlyB(int v) : val(v) {} + MoveOnlyB(MoveOnlyB&& rhs) : val(rhs.val) { rhs.val = 0; } + void operator=(MoveOnlyB&& rhs) {val = rhs.val; rhs.val = 0; } + MoveOnlyB(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; } + void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; } + +private: + MoveOnlyB(MoveOnlyB const&); + void operator=(MoveOnlyB const&); + MoveOnlyB(MoveOnly const&); + void operator=(MoveOnly const&); +}; + +void test_move_assign_from_optional_U() +{ + optional a((MoveOnly(2))); + optional b1; + b1 = boost::move(a); + + BOOST_CHECK(b1); + BOOST_CHECK(b1->val == 2); + BOOST_CHECK(a); + BOOST_CHECK(a->val == 0); + + b1 = MoveOnly(4); + + BOOST_CHECK(b1); + BOOST_CHECK(b1->val == 4); +} + +void test_move_ctor_from_optional_U() +{ + optional a((MoveOnly(2))); + optional b1(boost::move(a)); + + BOOST_CHECK(b1); + BOOST_CHECK(b1->val == 2); + BOOST_CHECK(a); + BOOST_CHECK(a->val == 0); + + optional b2(( optional(( MoveOnly(4) )) )); + + BOOST_CHECK(b2); + BOOST_CHECK(b2->val == 4); +} + // these 4 classes have different noexcept signatures in move operations struct NothrowBoth { NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; @@ -312,9 +364,11 @@ int test_main( int, char* [] ) test_move_ctor_from_U(); test_move_ctor_form_T(); test_move_ctor_from_optional_T(); + test_move_ctor_from_optional_U(); test_move_assign_from_U(); test_move_assign_from_T(); test_move_assign_from_optional_T(); + test_move_assign_from_optional_U(); test_with_move_only(); #endif }