diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 053486e..a8ba5e6 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -146,6 +148,7 @@ struct types_when_isnt_ref typedef T * pointer_type ; typedef T const& argument_type ; } ; + template struct types_when_is_ref { @@ -162,6 +165,14 @@ struct types_when_is_ref typedef raw_type& argument_type ; } ; +template +void prevent_binding_rvalue_ref_to_optional_lvalue_ref() +{ + BOOST_STATIC_ASSERT_MSG( + !boost::is_lvalue_reference::value || !boost::is_rvalue_reference::value, + "binding rvalue references to optional lvalue references is disallowed"); +} + struct optional_tag {} ; template @@ -272,7 +283,7 @@ class optional_base : public optional_tag #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - template + template explicit optional_base ( Expr&& expr, PtrExpr const* tag ) : m_initialized(false) @@ -695,7 +706,8 @@ class optional : public optional_detail::optional_base #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Creates an optional initialized with 'move(val)'. // Can throw if T::T(T &&) does - optional ( rval_reference_type val ) : base( boost::forward(val) ) {} + optional ( rval_reference_type val ) : base( boost::forward(val) ) + {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref();} #endif // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. @@ -740,22 +752,23 @@ class optional : public optional_detail::optional_base // even though explicit overloads are present for these. // Depending on the above some T ctor is called. // Can throw if the resolved T ctor throws. -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template explicit optional ( Expr&& expr, - typename boost::disable_if_c< - (boost::is_base_of::type>::value) || - boost::is_same::type, none_t>::value >::type* = 0 + BOOST_DEDUCED_TYPENAME boost::disable_if_c< + (boost::is_base_of::type>::value) || + boost::is_same::type, none_t>::value >::type* = 0 ) - : base(boost::forward(expr),boost::addressof(expr)) {} + : base(boost::forward(expr),boost::addressof(expr)) + {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref();} #else template explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} -#endif -#endif +#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // !defined BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT // Creates a deep copy of another optional // Can throw if T::T(T const&) does @@ -779,12 +792,14 @@ class optional : public optional_detail::optional_base #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template - typename boost::disable_if_c< - boost::is_base_of::type>::value || boost::is_same::type, none_t>::value, + BOOST_DEDUCED_TYPENAME boost::disable_if_c< + boost::is_base_of::type>::value || + boost::is_same::type, none_t>::value, optional& >::type operator= ( Expr&& expr ) { + optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref(); this->assign_expr(boost::forward(expr),boost::addressof(expr)); return *this ; } @@ -836,7 +851,7 @@ class optional : public optional_detail::optional_base return *this ; } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Assigns from a T (deep-moves the rhs value) optional& operator= ( rval_reference_type val ) { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e7e53fa..ac8017e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -32,5 +32,9 @@ import testing ; [ 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 ] + [ 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 ] ; } diff --git a/test/optional_test_ref_fail_assign_from_Trefref.cpp b/test/optional_test_ref_fail_assign_from_Trefref.cpp new file mode 100644 index 0000000..4eb748a --- /dev/null +++ b/test/optional_test_ref_fail_assign_from_Trefref.cpp @@ -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 opt; + opt = int(3); +} + +#else +# error "Test skipped. This cannot be implemented w/o rvalue references." +#endif diff --git a/test/optional_test_ref_fail_assign_from_Urefref.cpp b/test/optional_test_ref_fail_assign_from_Urefref.cpp new file mode 100644 index 0000000..b06185f --- /dev/null +++ b/test/optional_test_ref_fail_assign_from_Urefref.cpp @@ -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 opt; + opt = long(3); +} + +#else +# error "Test skipped. This cannot be implemented w/o rvalue references." +#endif diff --git a/test/optional_test_ref_fail_init_from_Trefref.cpp b/test/optional_test_ref_fail_init_from_Trefref.cpp new file mode 100644 index 0000000..05752b8 --- /dev/null +++ b/test/optional_test_ref_fail_init_from_Trefref.cpp @@ -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 opt = int(3); +} + +#else +# error "Test skipped. This cannot be implemented w/o rvalue references." +#endif diff --git a/test/optional_test_ref_fail_init_from_Urefref.cpp b/test/optional_test_ref_fail_init_from_Urefref.cpp new file mode 100644 index 0000000..e15192b --- /dev/null +++ b/test/optional_test_ref_fail_init_from_Urefref.cpp @@ -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 opt = long(3); +} + +#else +# error "Test skipped. This cannot be implemented w/o rvalue references." +#endif