forked from boostorg/optional
Added more tests for move operations, fixed bugs, disabled optional<T&&>.
This commit is contained in:
@ -21,13 +21,14 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type.hpp>
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <boost/type_traits/has_nothrow_constructor.hpp>
|
||||
#include <boost/type_traits/type_with_alignment.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/type_traits/is_reference.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
@ -139,6 +140,7 @@ struct types_when_isnt_ref
|
||||
typedef T & reference_type ;
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
typedef T && rval_reference_type ;
|
||||
static rval_reference_type move(reference_type r) { return boost::move(r); }
|
||||
#endif
|
||||
typedef T const* pointer_const_type ;
|
||||
typedef T * pointer_type ;
|
||||
@ -153,6 +155,7 @@ struct types_when_is_ref
|
||||
typedef raw_type& reference_type ;
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
typedef raw_type&& rval_reference_type ;
|
||||
static reference_type move(reference_type r) { return r; }
|
||||
#endif
|
||||
typedef raw_type* pointer_const_type ;
|
||||
typedef raw_type* pointer_type ;
|
||||
@ -310,6 +313,24 @@ class optional_base : public optional_tag
|
||||
construct(rhs.get_impl());
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
// Assigns from another optional<T> (deep-moves the rhs value)
|
||||
void assign ( optional_base&& rhs )
|
||||
{
|
||||
if (is_initialized())
|
||||
{
|
||||
if ( rhs.is_initialized() )
|
||||
assign_value(boost::move(rhs.get_impl()), is_reference_predicate() );
|
||||
else destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rhs.is_initialized() )
|
||||
construct(boost::move(rhs.get_impl()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assigns from another _convertible_ optional<U> (deep-copies the rhs value)
|
||||
template<class U>
|
||||
@ -328,7 +349,7 @@ class optional_base : public optional_tag
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
// move-assigns from another _convertible_ optional<U> (deep-moves from the rhs value)
|
||||
template<class U>
|
||||
void assign ( optional<U>&& rhs )
|
||||
@ -420,7 +441,7 @@ class optional_base : public optional_tag
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
void construct ( rval_reference_type val )
|
||||
{
|
||||
new (m_storage.address()) internal_type( boost::move(val) ) ;
|
||||
new (m_storage.address()) internal_type( types::move(val) ) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
#endif
|
||||
@ -726,7 +747,6 @@ class optional : public optional_detail::optional_base<T>
|
||||
explicit optional ( Expr&& expr,
|
||||
typename boost::disable_if_c<
|
||||
(boost::is_base_of<optional_detail::optional_tag, typename boost::decay<Expr>::type>::value) ||
|
||||
boost::is_same<typename boost::decay<Expr>::type, optional>::value ||
|
||||
boost::is_same<typename boost::decay<Expr>::type, none_t>::value >::type* = 0
|
||||
)
|
||||
: base(boost::forward<Expr>(expr),boost::addressof(expr)) {}
|
||||
@ -760,7 +780,7 @@ class optional : public optional_detail::optional_base<T>
|
||||
|
||||
template<class Expr>
|
||||
typename boost::disable_if_c<
|
||||
boost::is_base_of<optional_detail::optional_tag, typename boost::decay<Expr>::type>::value || boost::is_same<typename boost::decay<Expr>::type, optional>::value || boost::is_same<typename boost::decay<Expr>::type, none_t>::value,
|
||||
boost::is_base_of<optional_detail::optional_tag, typename boost::decay<Expr>::type>::value || boost::is_same<typename boost::decay<Expr>::type, none_t>::value,
|
||||
optional&
|
||||
>::type
|
||||
operator= ( Expr&& expr )
|
||||
@ -873,6 +893,14 @@ class optional : public optional_detail::optional_base<T>
|
||||
bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; }
|
||||
} ;
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<class T>
|
||||
class optional<T&&>
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) == 0, "Optional rvalue references are illegal.");
|
||||
} ;
|
||||
#endif
|
||||
|
||||
// Returns optional<T>(v)
|
||||
template<class T>
|
||||
inline
|
||||
|
@ -30,5 +30,7 @@ import testing ;
|
||||
[ compile-fail optional_test_ref_fail4.cpp ]
|
||||
[ compile-fail optional_test_inplace_fail.cpp ]
|
||||
[ compile-fail optional_test_inplace_fail2.cpp ]
|
||||
[ compile-fail optional_test_fail_copying_a_moveable_type.cpp ]
|
||||
[ compile-fail optional_test_fail_optional_rvalue_ref.cpp ]
|
||||
;
|
||||
}
|
||||
|
36
test/optional_test_fail_copying_a_moveable_type.cpp
Normal file
36
test/optional_test_fail_copying_a_moveable_type.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2014, Andrzej Krzemienski.
|
||||
//
|
||||
// Use, modification, and distribution is subject to 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)
|
||||
//
|
||||
// See http://www.boost.org/lib/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
//
|
||||
#include "boost/optional.hpp"
|
||||
|
||||
class MoveOnly
|
||||
{
|
||||
public:
|
||||
int val;
|
||||
MoveOnly(int v) : val(v) {}
|
||||
MoveOnly(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; }
|
||||
void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; }
|
||||
|
||||
private:
|
||||
MoveOnly(MoveOnly const&);
|
||||
void operator=(MoveOnly const&);
|
||||
};
|
||||
|
||||
//
|
||||
// THIS TEST SHOULD FAIL TO COMPILE
|
||||
//
|
||||
void test_copying_optional_with_noncopyable_T()
|
||||
{
|
||||
boost::optional<MoveOnly> opt1 ;
|
||||
boost::optional<MoveOnly> opt2(opt1) ;
|
||||
}
|
||||
|
||||
|
19
test/optional_test_fail_optional_rvalue_ref.cpp
Normal file
19
test/optional_test_fail_optional_rvalue_ref.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (C) 2014, Andrzej Krzemienski.
|
||||
//
|
||||
// Use, modification, and distribution is subject to 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)
|
||||
//
|
||||
// See http://www.boost.org/lib/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// akrzemi1@gmail.com
|
||||
//
|
||||
#include "boost/optional.hpp"
|
||||
//
|
||||
// THIS TEST SHOULD FAIL TO COMPILE
|
||||
//
|
||||
|
||||
boost::optional<int&&> oi;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin
|
||||
#include "boost/mpl/bool.hpp"
|
||||
#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_
|
||||
#include "boost/static_assert.hpp"
|
||||
|
||||
#include "boost/optional/optional.hpp"
|
||||
|
||||
@ -91,7 +92,6 @@ void test_move_ctor_from_U()
|
||||
OracleVal v1;
|
||||
optional<Oracle> o2 (v1);
|
||||
BOOST_CHECK(o2);
|
||||
std::cout << "AK" << " @@@ " << o2->s << std::endl;
|
||||
BOOST_CHECK(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed );
|
||||
BOOST_CHECK(v1.s == sIntConstructed);
|
||||
|
||||
@ -204,7 +204,7 @@ void test_move_assign_from_T()
|
||||
BOOST_CHECK(v1.s == sMovedFrom);
|
||||
}
|
||||
|
||||
void test_move_ssign_from_optional_T()
|
||||
void test_move_assign_from_optional_T()
|
||||
{
|
||||
optional<Oracle> o1;
|
||||
optional<Oracle> o2;
|
||||
@ -212,8 +212,8 @@ void test_move_ssign_from_optional_T()
|
||||
BOOST_CHECK(!o1);
|
||||
optional<Oracle> o3((Oracle()));
|
||||
o1 = o3;
|
||||
/*BOOST_CHECK(o3);
|
||||
BOOST_CHECK(o3->s == sDefaultConstructed);
|
||||
BOOST_CHECK(o3);
|
||||
BOOST_CHECK(o3->s == sMoveConstructed);
|
||||
BOOST_CHECK(o1);
|
||||
BOOST_CHECK(o1->s == sCopyConstructed);
|
||||
|
||||
@ -225,9 +225,82 @@ void test_move_ssign_from_optional_T()
|
||||
|
||||
o2 = optional<Oracle>((Oracle()));
|
||||
BOOST_CHECK(o2);
|
||||
BOOST_CHECK(o2->s == sMoveAssigned);*/
|
||||
BOOST_CHECK(o2->s == sMoveAssigned);
|
||||
}
|
||||
|
||||
class MoveOnly
|
||||
{
|
||||
public:
|
||||
int val;
|
||||
MoveOnly(int v) : val(v) {}
|
||||
MoveOnly(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; }
|
||||
void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; }
|
||||
|
||||
private:
|
||||
MoveOnly(MoveOnly const&);
|
||||
void operator=(MoveOnly const&);
|
||||
};
|
||||
|
||||
void test_with_move_only()
|
||||
{
|
||||
optional<MoveOnly> o1;
|
||||
optional<MoveOnly> o2((MoveOnly(1)));
|
||||
BOOST_CHECK(o2);
|
||||
BOOST_CHECK(o2->val == 1);
|
||||
optional<MoveOnly> o3 (boost::move(o1));
|
||||
BOOST_CHECK(!o3);
|
||||
optional<MoveOnly> o4 (boost::move(o2));
|
||||
BOOST_CHECK(o4);
|
||||
BOOST_CHECK(o4->val == 1);
|
||||
BOOST_CHECK(o2);
|
||||
BOOST_CHECK(o2->val == 0);
|
||||
|
||||
o3 = boost::move(o4);
|
||||
BOOST_CHECK(o3);
|
||||
BOOST_CHECK(o3->val == 1);
|
||||
BOOST_CHECK(o4);
|
||||
BOOST_CHECK(o4->val == 0);
|
||||
}
|
||||
|
||||
// these 4 classes have different noexcept signatures in move operations
|
||||
struct NothrowBoth {
|
||||
NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {};
|
||||
void operator=(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {};
|
||||
};
|
||||
struct NothrowCtor {
|
||||
NothrowCtor(NothrowCtor&&) BOOST_NOEXCEPT_IF(true) {};
|
||||
void operator=(NothrowCtor&&) BOOST_NOEXCEPT_IF(false) {};
|
||||
};
|
||||
struct NothrowAssign {
|
||||
NothrowAssign(NothrowAssign&&) BOOST_NOEXCEPT_IF(false) {};
|
||||
void operator=(NothrowAssign&&) BOOST_NOEXCEPT_IF(true) {};
|
||||
};
|
||||
struct NothrowNone {
|
||||
NothrowNone(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {};
|
||||
void operator=(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {};
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_NOEXCEPT
|
||||
|
||||
void test_noexcept() // this is a compile-time test
|
||||
{
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible<optional<NothrowBoth> >::value);
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable<optional<NothrowBoth> >::value);
|
||||
BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional<NothrowBoth>()));
|
||||
|
||||
BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible<optional<NothrowCtor> >::value);
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable<optional<NothrowCtor> >::value);
|
||||
BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional<NothrowCtor>()));
|
||||
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible<optional<NothrowAssign> >::value);
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable<optional<NothrowAssign> >::value);
|
||||
BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional<NothrowAssign>()));
|
||||
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible<optional<NothrowNone> >::value);
|
||||
BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable<optional<NothrowNone> >::value);
|
||||
BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional<NothrowNone>()));
|
||||
}
|
||||
#endif // !defned BOOST_NO_NOEXCEPT
|
||||
|
||||
#endif
|
||||
|
||||
@ -241,7 +314,8 @@ int test_main( int, char* [] )
|
||||
test_move_ctor_from_optional_T();
|
||||
test_move_assign_from_U();
|
||||
test_move_assign_from_T();
|
||||
test_move_ssign_from_optional_T();
|
||||
test_move_assign_from_optional_T();
|
||||
test_with_move_only();
|
||||
#endif
|
||||
}
|
||||
catch ( ... )
|
||||
|
Reference in New Issue
Block a user