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/config.hpp>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/static_assert.hpp>
|
||||||
#include <boost/type.hpp>
|
#include <boost/type.hpp>
|
||||||
#include <boost/type_traits/alignment_of.hpp>
|
#include <boost/type_traits/alignment_of.hpp>
|
||||||
#include <boost/type_traits/has_nothrow_constructor.hpp>
|
#include <boost/type_traits/has_nothrow_constructor.hpp>
|
||||||
#include <boost/type_traits/type_with_alignment.hpp>
|
#include <boost/type_traits/type_with_alignment.hpp>
|
||||||
#include <boost/type_traits/remove_reference.hpp>
|
#include <boost/type_traits/remove_reference.hpp>
|
||||||
#include <boost/type_traits/decay.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_reference.hpp>
|
||||||
#include <boost/type_traits/is_same.hpp>
|
#include <boost/type_traits/is_same.hpp>
|
||||||
#include <boost/mpl/if.hpp>
|
#include <boost/mpl/if.hpp>
|
||||||
@ -139,6 +140,7 @@ struct types_when_isnt_ref
|
|||||||
typedef T & reference_type ;
|
typedef T & reference_type ;
|
||||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||||
typedef T && rval_reference_type ;
|
typedef T && rval_reference_type ;
|
||||||
|
static rval_reference_type move(reference_type r) { return boost::move(r); }
|
||||||
#endif
|
#endif
|
||||||
typedef T const* pointer_const_type ;
|
typedef T const* pointer_const_type ;
|
||||||
typedef T * pointer_type ;
|
typedef T * pointer_type ;
|
||||||
@ -153,6 +155,7 @@ struct types_when_is_ref
|
|||||||
typedef raw_type& reference_type ;
|
typedef raw_type& reference_type ;
|
||||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||||
typedef raw_type&& rval_reference_type ;
|
typedef raw_type&& rval_reference_type ;
|
||||||
|
static reference_type move(reference_type r) { return r; }
|
||||||
#endif
|
#endif
|
||||||
typedef raw_type* pointer_const_type ;
|
typedef raw_type* pointer_const_type ;
|
||||||
typedef raw_type* pointer_type ;
|
typedef raw_type* pointer_type ;
|
||||||
@ -311,6 +314,24 @@ class optional_base : public optional_tag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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)
|
// Assigns from another _convertible_ optional<U> (deep-copies the rhs value)
|
||||||
template<class U>
|
template<class U>
|
||||||
void assign ( optional<U> const& rhs )
|
void assign ( optional<U> const& rhs )
|
||||||
@ -420,7 +441,7 @@ class optional_base : public optional_tag
|
|||||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||||
void construct ( rval_reference_type val )
|
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 ;
|
m_initialized = true ;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -726,7 +747,6 @@ class optional : public optional_detail::optional_base<T>
|
|||||||
explicit optional ( Expr&& expr,
|
explicit optional ( Expr&& expr,
|
||||||
typename boost::disable_if_c<
|
typename boost::disable_if_c<
|
||||||
(boost::is_base_of<optional_detail::optional_tag, typename boost::decay<Expr>::type>::value) ||
|
(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
|
boost::is_same<typename boost::decay<Expr>::type, none_t>::value >::type* = 0
|
||||||
)
|
)
|
||||||
: base(boost::forward<Expr>(expr),boost::addressof(expr)) {}
|
: base(boost::forward<Expr>(expr),boost::addressof(expr)) {}
|
||||||
@ -760,7 +780,7 @@ class optional : public optional_detail::optional_base<T>
|
|||||||
|
|
||||||
template<class Expr>
|
template<class Expr>
|
||||||
typename boost::disable_if_c<
|
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&
|
optional&
|
||||||
>::type
|
>::type
|
||||||
operator= ( Expr&& expr )
|
operator= ( Expr&& expr )
|
||||||
@ -873,6 +893,14 @@ class optional : public optional_detail::optional_base<T>
|
|||||||
bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; }
|
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)
|
// Returns optional<T>(v)
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
inline
|
||||||
|
@ -30,5 +30,7 @@ import testing ;
|
|||||||
[ compile-fail optional_test_ref_fail4.cpp ]
|
[ compile-fail optional_test_ref_fail4.cpp ]
|
||||||
[ compile-fail optional_test_inplace_fail.cpp ]
|
[ compile-fail optional_test_inplace_fail.cpp ]
|
||||||
[ compile-fail optional_test_inplace_fail2.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/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.hpp"
|
||||||
#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_
|
#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_
|
||||||
|
#include "boost/static_assert.hpp"
|
||||||
|
|
||||||
#include "boost/optional/optional.hpp"
|
#include "boost/optional/optional.hpp"
|
||||||
|
|
||||||
@ -91,7 +92,6 @@ void test_move_ctor_from_U()
|
|||||||
OracleVal v1;
|
OracleVal v1;
|
||||||
optional<Oracle> o2 (v1);
|
optional<Oracle> o2 (v1);
|
||||||
BOOST_CHECK(o2);
|
BOOST_CHECK(o2);
|
||||||
std::cout << "AK" << " @@@ " << o2->s << std::endl;
|
|
||||||
BOOST_CHECK(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed );
|
BOOST_CHECK(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed );
|
||||||
BOOST_CHECK(v1.s == sIntConstructed);
|
BOOST_CHECK(v1.s == sIntConstructed);
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ void test_move_assign_from_T()
|
|||||||
BOOST_CHECK(v1.s == sMovedFrom);
|
BOOST_CHECK(v1.s == sMovedFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_move_ssign_from_optional_T()
|
void test_move_assign_from_optional_T()
|
||||||
{
|
{
|
||||||
optional<Oracle> o1;
|
optional<Oracle> o1;
|
||||||
optional<Oracle> o2;
|
optional<Oracle> o2;
|
||||||
@ -212,8 +212,8 @@ void test_move_ssign_from_optional_T()
|
|||||||
BOOST_CHECK(!o1);
|
BOOST_CHECK(!o1);
|
||||||
optional<Oracle> o3((Oracle()));
|
optional<Oracle> o3((Oracle()));
|
||||||
o1 = o3;
|
o1 = o3;
|
||||||
/*BOOST_CHECK(o3);
|
BOOST_CHECK(o3);
|
||||||
BOOST_CHECK(o3->s == sDefaultConstructed);
|
BOOST_CHECK(o3->s == sMoveConstructed);
|
||||||
BOOST_CHECK(o1);
|
BOOST_CHECK(o1);
|
||||||
BOOST_CHECK(o1->s == sCopyConstructed);
|
BOOST_CHECK(o1->s == sCopyConstructed);
|
||||||
|
|
||||||
@ -225,9 +225,82 @@ void test_move_ssign_from_optional_T()
|
|||||||
|
|
||||||
o2 = optional<Oracle>((Oracle()));
|
o2 = optional<Oracle>((Oracle()));
|
||||||
BOOST_CHECK(o2);
|
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
|
#endif
|
||||||
|
|
||||||
@ -241,7 +314,8 @@ int test_main( int, char* [] )
|
|||||||
test_move_ctor_from_optional_T();
|
test_move_ctor_from_optional_T();
|
||||||
test_move_assign_from_U();
|
test_move_assign_from_U();
|
||||||
test_move_assign_from_T();
|
test_move_assign_from_T();
|
||||||
test_move_ssign_from_optional_T();
|
test_move_assign_from_optional_T();
|
||||||
|
test_with_move_only();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch ( ... )
|
catch ( ... )
|
||||||
|
Reference in New Issue
Block a user