Added tests for move conversion between optional<T> and optional<U>

This commit is contained in:
Andrzej Krzemienski
2014-04-28 16:51:49 +02:00
parent 3816143646
commit 01b22a0ff0
2 changed files with 82 additions and 1 deletions

View File

@ -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 // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error
// instead of choosing the wrong overload // instead of choosing the wrong overload
// //
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
// Notice that 'Expr' will be optional<T> or optional<U> (but not optional_base<..>)
template<class Expr>
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<T> or optional<U> (but not optional_base<..>) // Notice that 'Expr' will be optional<T> or optional<U> (but not optional_base<..>)
template<class Expr> template<class Expr>
void construct ( Expr const& expr, optional_tag const* ) void construct ( Expr const& expr, optional_tag const* )
@ -600,6 +614,7 @@ class optional_base : public optional_tag
} }
} }
#endif #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_not_reference_tag ) { get_impl() = val; }
void assign_value ( argument_type val, is_reference_tag ) { construct(val); } void assign_value ( argument_type val, is_reference_tag ) { construct(val); }
@ -814,7 +829,7 @@ class optional : public optional_detail::optional_base<T>
#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES #endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES
#endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) #endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION)
// Assigns from another convertible optional<U> (converts && deep-copies the rhs value) // Copy-assigns from another convertible optional<U> (converts && deep-copies the rhs value)
// Requires a valid conversion from U to T. // Requires a valid conversion from U to T.
// Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED
template<class U> template<class U>
@ -823,6 +838,18 @@ class optional : public optional_detail::optional_base<T>
this->assign(rhs); this->assign(rhs);
return *this ; return *this ;
} }
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
// Move-assigns from another convertible optional<U> (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<class U>
optional& operator= ( optional<U> && rhs )
{
this->assign(boost::move(rhs));
return *this ;
}
#endif
// Assigns from another optional<T> (deep-copies the rhs value) // Assigns from another optional<T> (deep-copies the rhs value)
// Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED

View File

@ -239,6 +239,8 @@ public:
private: private:
MoveOnly(MoveOnly const&); MoveOnly(MoveOnly const&);
void operator=(MoveOnly const&); void operator=(MoveOnly const&);
friend class MoveOnlyB;
}; };
void test_with_move_only() void test_with_move_only()
@ -262,6 +264,56 @@ void test_with_move_only()
BOOST_CHECK(o4->val == 0); 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<MoveOnly> a((MoveOnly(2)));
optional<MoveOnlyB> 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<MoveOnly> a((MoveOnly(2)));
optional<MoveOnlyB> b1(boost::move(a));
BOOST_CHECK(b1);
BOOST_CHECK(b1->val == 2);
BOOST_CHECK(a);
BOOST_CHECK(a->val == 0);
optional<MoveOnlyB> b2(( optional<MoveOnly>(( MoveOnly(4) )) ));
BOOST_CHECK(b2);
BOOST_CHECK(b2->val == 4);
}
// these 4 classes have different noexcept signatures in move operations // these 4 classes have different noexcept signatures in move operations
struct NothrowBoth { struct NothrowBoth {
NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {};
@ -312,9 +364,11 @@ int test_main( int, char* [] )
test_move_ctor_from_U(); test_move_ctor_from_U();
test_move_ctor_form_T(); test_move_ctor_form_T();
test_move_ctor_from_optional_T(); test_move_ctor_from_optional_T();
test_move_ctor_from_optional_U();
test_move_assign_from_U(); test_move_assign_from_U();
test_move_assign_from_T(); test_move_assign_from_T();
test_move_assign_from_optional_T(); test_move_assign_from_optional_T();
test_move_assign_from_optional_U();
test_with_move_only(); test_with_move_only();
#endif #endif
} }