Disabled assignment and construction from rvalue references in optional<const T&>

This commit is contained in:
Andrzej Krzemienski
2014-04-28 15:48:55 +02:00
parent 0e61751fab
commit 3816143646
6 changed files with 133 additions and 12 deletions

View File

@ -29,7 +29,9 @@
#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_lvalue_reference.hpp>
#include <boost/type_traits/is_reference.hpp> #include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/is_rvalue_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>
#include <boost/mpl/bool.hpp> #include <boost/mpl/bool.hpp>
@ -146,6 +148,7 @@ struct types_when_isnt_ref
typedef T * pointer_type ; typedef T * pointer_type ;
typedef T const& argument_type ; typedef T const& argument_type ;
} ; } ;
template<class T> template<class T>
struct types_when_is_ref struct types_when_is_ref
{ {
@ -162,6 +165,14 @@ struct types_when_is_ref
typedef raw_type& argument_type ; typedef raw_type& argument_type ;
} ; } ;
template <class To, class From>
void prevent_binding_rvalue_ref_to_optional_lvalue_ref()
{
BOOST_STATIC_ASSERT_MSG(
!boost::is_lvalue_reference<To>::value || !boost::is_rvalue_reference<From>::value,
"binding rvalue references to optional lvalue references is disallowed");
}
struct optional_tag {} ; struct optional_tag {} ;
template<class T> template<class T>
@ -272,7 +283,7 @@ class optional_base : public optional_tag
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template<class Expr, typename PtrExpr> template<class Expr, class PtrExpr>
explicit optional_base ( Expr&& expr, PtrExpr const* tag ) explicit optional_base ( Expr&& expr, PtrExpr const* tag )
: :
m_initialized(false) m_initialized(false)
@ -695,7 +706,8 @@ class optional : public optional_detail::optional_base<T>
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
// Creates an optional<T> initialized with 'move(val)'. // Creates an optional<T> initialized with 'move(val)'.
// Can throw if T::T(T &&) does // Can throw if T::T(T &&) does
optional ( rval_reference_type val ) : base( boost::forward<T>(val) ) {} optional ( rval_reference_type val ) : base( boost::forward<T>(val) )
{optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>();}
#endif #endif
// Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional.
@ -745,17 +757,18 @@ class optional : public optional_detail::optional_base<T>
template<class Expr> template<class Expr>
explicit optional ( Expr&& expr, explicit optional ( Expr&& expr,
typename boost::disable_if_c< BOOST_DEDUCED_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, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value) ||
boost::is_same<typename boost::decay<Expr>::type, none_t>::value >::type* = 0 boost::is_same<BOOST_DEDUCED_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))
{optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>();}
#else #else
template<class Expr> template<class Expr>
explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {}
#endif #endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES
#endif #endif // !defined BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
// Creates a deep copy of another optional<T> // Creates a deep copy of another optional<T>
// Can throw if T::T(T const&) does // Can throw if T::T(T const&) does
@ -779,12 +792,14 @@ class optional : public optional_detail::optional_base<T>
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template<class Expr> template<class Expr>
typename boost::disable_if_c< BOOST_DEDUCED_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, none_t>::value, boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value ||
boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value,
optional& optional&
>::type >::type
operator= ( Expr&& expr ) operator= ( Expr&& expr )
{ {
optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>();
this->assign_expr(boost::forward<Expr>(expr),boost::addressof(expr)); this->assign_expr(boost::forward<Expr>(expr),boost::addressof(expr));
return *this ; return *this ;
} }

View File

@ -32,5 +32,9 @@ import testing ;
[ 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_copying_a_moveable_type.cpp ]
[ compile-fail optional_test_fail_optional_rvalue_ref.cpp ] [ compile-fail optional_test_fail_optional_rvalue_ref.cpp ]
[ compile-fail optional_test_ref_fail_init_from_Trefref.cpp ]
[ compile-fail optional_test_ref_fail_init_from_Urefref.cpp ]
[ compile-fail optional_test_ref_fail_assign_from_Trefref.cpp ]
[ compile-fail optional_test_ref_fail_assign_from_Urefref.cpp ]
; ;
} }

View File

@ -0,0 +1,26 @@
// 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"
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void optional_reference__test_no_assign_from_Trefref()
{
boost::optional<const int&> opt;
opt = int(3);
}
#else
# error "Test skipped. This cannot be implemented w/o rvalue references."
#endif

View File

@ -0,0 +1,26 @@
// 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"
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void optional_reference__test_no_assign_from_Urefref()
{
boost::optional<const int&> opt;
opt = long(3);
}
#else
# error "Test skipped. This cannot be implemented w/o rvalue references."
#endif

View File

@ -0,0 +1,25 @@
// 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"
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void optional_reference__test_no_init_from_Trefref()
{
boost::optional<const int&> opt = int(3);
}
#else
# error "Test skipped. This cannot be implemented w/o rvalue references."
#endif

View File

@ -0,0 +1,25 @@
// 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"
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void optional_reference__test_no_init_from_Urefref()
{
boost::optional<const int&> opt = long(3);
}
#else
# error "Test skipped. This cannot be implemented w/o rvalue references."
#endif