diff --git a/doc/91_relnotes.qbk b/doc/91_relnotes.qbk index 666571c..3cffa97 100644 --- a/doc/91_relnotes.qbk +++ b/doc/91_relnotes.qbk @@ -16,6 +16,7 @@ * `boost::none_t` is no longer convertible from literal `0`. This avoids a bug where `optional> oi = 0;` would initialize an optional object with no contained value. * Improved the trick that prevents streaming out `optional` without header `optional_io.hpp` by using safe-bool idiom. This addresses [@https://svn.boost.org/trac/boost/ticket/10825 Trac #10825] * IOStream operators are now mentioned in documentation. +* Added a way to manually disable move semantics: just define macro `BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES`. This can be used to work around [@https://svn.boost.org/trac/boost/ticket/10399 Trac #10399] [heading Boost Release 1.57] diff --git a/doc/html/boost_optional/relnotes.html b/doc/html/boost_optional/relnotes.html index 9f498df..02fcd41 100644 --- a/doc/html/boost_optional/relnotes.html +++ b/doc/html/boost_optional/relnotes.html @@ -47,6 +47,11 @@
  • IOStream operators are now mentioned in documentation.
  • +
  • + Added a way to manually disable move semantics: just define macro BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES. + This can be used to work around Trac + #10399 +
  • diff --git a/doc/html/index.html b/doc/html/index.html index e840af1..3abdc22 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -138,7 +138,7 @@ - +

    Last revised: January 20, 2015 at 23:06:39 GMT

    Last revised: January 21, 2015 at 13:59:23 GMT


    diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 580c87d..f8d631d 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. -// Copyright (C) 2014 Andrzej Krzemienski. +// Copyright (C) 2014, 2015 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 @@ -57,6 +57,10 @@ #include +#if (defined BOOST_NO_CXX11_RVALUE_REFERENCES) || (defined BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES) +#define BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES +#endif + #if BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION,<=700) // AFAICT only Intel 7 correctly resolves the overload set // that includes the in-place factory taking functions, @@ -148,7 +152,7 @@ struct types_when_isnt_ref { typedef T const& reference_const_type ; typedef T & reference_type ; -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES typedef T && rval_reference_type ; typedef T && reference_type_of_temporary_wrapper; #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES @@ -171,7 +175,7 @@ struct types_when_is_ref typedef raw_type& reference_const_type ; typedef raw_type& reference_type ; -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES typedef BOOST_DEDUCED_TYPENAME remove_const::type&& rval_reference_type ; typedef raw_type& reference_type_of_temporary_wrapper; static reference_type move(reference_type r) { return r; } @@ -226,7 +230,7 @@ class optional_base : public optional_tag protected: typedef BOOST_DEDUCED_TYPENAME types::reference_type reference_type ; typedef BOOST_DEDUCED_TYPENAME types::reference_const_type reference_const_type ; -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES typedef BOOST_DEDUCED_TYPENAME types::rval_reference_type rval_reference_type ; typedef BOOST_DEDUCED_TYPENAME types::reference_type_of_temporary_wrapper reference_type_of_temporary_wrapper ; #endif @@ -255,7 +259,7 @@ class optional_base : public optional_tag construct(val); } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // move-construct an optional initialized from an rvalue-ref to 'val'. // Can throw if T::T(T&&) does optional_base ( rval_reference_type val ) @@ -286,7 +290,7 @@ class optional_base : public optional_tag construct(rhs.get_impl()); } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Creates a deep move of another optional // Can throw if T::T(T&&) does optional_base ( optional_base&& rhs ) @@ -298,7 +302,7 @@ class optional_base : public optional_tag } #endif -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES template explicit optional_base ( Expr&& expr, PtrExpr const* tag ) @@ -342,7 +346,7 @@ class optional_base : public optional_tag } } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Assigns from another optional (deep-moves the rhs value) void assign ( optional_base&& rhs ) { @@ -377,7 +381,7 @@ class optional_base : public optional_tag } } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // move-assigns from another _convertible_ optional (deep-moves from the rhs value) template void assign ( optional&& rhs ) @@ -405,7 +409,7 @@ class optional_base : public optional_tag else construct(val); } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Assigns from a T (deep-moves the rhs value) void assign ( rval_reference_type val ) { @@ -421,7 +425,7 @@ class optional_base : public optional_tag #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES template void assign_expr ( Expr&& expr, ExprPtr const* tag ) { @@ -466,7 +470,7 @@ class optional_base : public optional_tag m_initialized = true ; } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES void construct ( rval_reference_type val ) { ::new (m_storage.address()) internal_type( types::move(val) ) ; @@ -475,7 +479,7 @@ class optional_base : public optional_tag #endif -#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) // Constructs in-place // upon exception *this is always uninitialized template @@ -485,7 +489,7 @@ class optional_base : public optional_tag ::new (m_storage.address()) internal_type( boost::forward(args)... ); m_initialized = true ; } -#elif (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) +#elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) template void emplace_assign ( Arg&& arg ) { @@ -513,7 +517,7 @@ class optional_base : public optional_tag #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Constructs in-place using the given factory template void construct ( Expr&& factory, in_place_factory_base const* ) @@ -584,7 +588,7 @@ class optional_base : public optional_tag #endif -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Constructs using any expression implicitly convertible to the single argument // of a one-argument T constructor. // Converting constructions of optional from optional uses this function with @@ -642,7 +646,7 @@ class optional_base : public optional_tag // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error // instead of choosing the wrong overload // -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Notice that 'Expr' will be optional or optional (but not optional_base<..>) template void construct ( Expr&& expr, optional_tag const* ) @@ -673,7 +677,7 @@ class optional_base : public optional_tag void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; } void assign_value ( argument_type val, is_reference_tag ) { construct(val); } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES void assign_value ( rval_reference_type val, is_not_reference_tag ) { get_impl() = static_cast(val); } void assign_value ( rval_reference_type val, is_reference_tag ) { construct( static_cast(val) ); } #endif @@ -750,7 +754,7 @@ class optional : public optional_detail::optional_base typedef BOOST_DEDUCED_TYPENAME base::value_type value_type ; typedef BOOST_DEDUCED_TYPENAME base::reference_type reference_type ; typedef BOOST_DEDUCED_TYPENAME base::reference_const_type reference_const_type ; -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES typedef BOOST_DEDUCED_TYPENAME base::rval_reference_type rval_reference_type ; typedef BOOST_DEDUCED_TYPENAME base::reference_type_of_temporary_wrapper reference_type_of_temporary_wrapper ; #endif @@ -770,7 +774,7 @@ class optional : public optional_detail::optional_base // Can throw if T::T(T const&) does optional ( argument_type val ) : base(val) {} -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_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) ) @@ -795,7 +799,7 @@ class optional : public optional_detail::optional_base this->construct(rhs.get()); } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Creates a deep move of another convertible optional // Requires a valid conversion from U to T. // Can throw if T::T(U&&) does @@ -819,7 +823,7 @@ 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_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES template @@ -834,14 +838,14 @@ class optional : public optional_detail::optional_base #else template explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} -#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // !defined BOOST_OPTIONAL_DETAIL_NO_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 optional ( optional const& rhs ) : base( static_cast(rhs) ) {} -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Creates a deep move of another optional // Can throw if T::T(T&&) does optional ( optional && rhs ) @@ -856,7 +860,7 @@ class optional : public optional_detail::optional_base #if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) // Assigns from an expression. See corresponding constructor. // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES template BOOST_DEDUCED_TYPENAME boost::disable_if_c< @@ -878,7 +882,7 @@ class optional : public optional_detail::optional_base this->assign_expr(expr,boost::addressof(expr)); return *this ; } -#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES #endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) // Copy-assigns from another convertible optional (converts && deep-copies the rhs value) @@ -891,7 +895,7 @@ class optional : public optional_detail::optional_base return *this ; } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Move-assigns from another convertible optional (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 @@ -912,7 +916,7 @@ class optional : public optional_detail::optional_base return *this ; } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Assigns from another optional (deep-moves the rhs value) optional& operator= ( optional && rhs ) BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value) @@ -930,7 +934,7 @@ class optional : public optional_detail::optional_base return *this ; } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Assigns from a T (deep-moves the rhs value) optional& operator= ( rval_reference_type val ) { @@ -949,7 +953,7 @@ class optional : public optional_detail::optional_base return *this ; } -#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) // Constructs in-place // upon exception *this is always uninitialized template @@ -957,7 +961,7 @@ class optional : public optional_detail::optional_base { this->emplace_assign( boost::forward(args)... ); } -#elif (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) +#elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) template void emplace ( Arg&& arg ) { @@ -1004,7 +1008,7 @@ class optional : public optional_detail::optional_base // Returns a reference to the value if this is initialized, otherwise, // the behaviour is UNDEFINED // No-throw -#ifndef BOOST_NO_CXX11_REF_QUALIFIERS +#if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) reference_const_type operator *() const& { return this->get() ; } reference_type operator *() & { return this->get() ; } reference_type_of_temporary_wrapper operator *() && { return boost::move(this->get()) ; } @@ -1013,7 +1017,7 @@ class optional : public optional_detail::optional_base reference_type operator *() { return this->get() ; } #endif // !defined BOOST_NO_CXX11_REF_QUALIFIERS -#ifndef BOOST_NO_CXX11_REF_QUALIFIERS +#if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) reference_const_type value() const& { if (this->is_initialized()) @@ -1075,7 +1079,7 @@ class optional : public optional_detail::optional_base else return boost::forward(v); } -#elif !defined BOOST_NO_CXX11_RVALUE_REFERENCES +#elif !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES template value_type value_or ( U&& v ) const { @@ -1130,7 +1134,7 @@ class optional : public optional_detail::optional_base BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() } ; -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES template class optional { @@ -1440,7 +1444,7 @@ struct swap_selector } }; -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES template<> struct swap_selector { @@ -1497,7 +1501,7 @@ struct swap_selector } } }; -#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES } // namespace optional_detail diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 366a2f0..accdd1a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -33,6 +33,7 @@ import testing ; [ run optional_test_value_access.cpp ] [ run optional_test_emplace.cpp ] [ run optional_test_minimum_requirements.cpp ] + [ run optional_test_msvc_bug_workaround.cpp ] [ compile-fail optional_test_fail1.cpp ] [ compile-fail optional_test_fail3a.cpp ] [ compile-fail optional_test_fail3b.cpp ] diff --git a/test/optional_test_msvc_bug_workaround.cpp b/test/optional_test_msvc_bug_workaround.cpp new file mode 100644 index 0000000..30f3b02 --- /dev/null +++ b/test/optional_test_msvc_bug_workaround.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2015 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 + +#define BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/lightweight_test.hpp" + + +struct Wrapper +{ + operator int () { return 9; } + operator boost::optional () { return 7; } +}; + +void test() +{ +#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) + boost::optional v = Wrapper(); + BOOST_TEST(v); + BOOST_TEST_EQ(*v, 7); +#endif +} + +int main() +{ + test(); + return boost::report_errors(); +} \ No newline at end of file