diff --git a/doc/20_reference.qbk b/doc/20_reference.qbk index cba3bac..8afc43b 100644 --- a/doc/20_reference.qbk +++ b/doc/20_reference.qbk @@ -602,10 +602,11 @@ __SPACE__ * [*Requires:] `T` is __COPY_CONSTRUCTIBLE__ and `CopyAssignable`. * [*Effects:] - * If `!*this && !rhs` no effect, otherwise - * if `bool(*this) && !rhs`, destroys the contained value by calling `val->T::~T()`, otherwise - * if `!*this && bool(rhs)`, initializes the contained value as if direct-initializing an object of type `T` with `*rhs`, otherwise - * (if `bool(*this) && bool(rhs)`) assigns `*rhs` to the contained value. +[table + [[][`*this` contains a value][`*this` does not contain a value]] + [[`rhs` contains a value][assigns `*rhs` to the contained value][initializes the contained value as if direct-initializing an object of type `T` with `*rhs`]] + [[`rhs` does not contain a value][destroys the contained value by calling `val->T::~T()`][no effect]] +] * [*Returns:] `*this`; * [*Postconditions:] `bool(rhs) == bool(*this)`. * [*Exception Safety:] If any exception is thrown, the initialization state of `*this` and `rhs` remains unchanged. @@ -662,10 +663,11 @@ __SPACE__ * [*Requires:] `T` is __MOVE_CONSTRUCTIBLE__ and `MoveAssignable`. * [*Effects:] - * If `!*this && !rhs` no effect, otherwise - * if `bool(*this) && !rhs`, destroys the contained value by calling `val->T::~T()`, otherwise - * if `!*this && bool(rhs)`, initializes the contained value as if direct-initializing an object of type `T` with `std::move(*rhs)`, otherwise - * (if `bool(*this) && bool(rhs)`) assigns `std::move(*rhs)` to the contained value. +[table + [[][`*this` contains a value][`*this` does not contain a value]] + [[`rhs` contains a value][assigns `std::move(*rhs)` to the contained value][initializes the contained value as if direct-initializing an object of type `T` with `std::move(*rhs)`]] + [[`rhs` does not contain a value][destroys the contained value by calling `val->T::~T()`][no effect]] +] * [*Returns:] `*this`; * [*Postconditions:] `bool(rhs) == bool(*this)`. * [*Remarks:] The expression inside `noexcept` is equivalent to `is_nothrow_move_constructible::value && is_nothrow_move_assignable::value`. @@ -696,21 +698,17 @@ __SPACE__ [: `template optional& optional::operator= ( optional const& rhs ) ;`] -* [*Effect:] Assigns another convertible optional to an optional. -* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and -its value is a ['copy] of the value of `rhs` ['converted] to type `T`; else -`*this` is uninitialized. -* [*Throws:] Whatever `T::operator=( U const& )` or `T::T( U const& )` throws. -* [*Notes:] If both `*this` and rhs are initially initialized, `T`'s -['assignment operator] (from `U`) is used. If `*this` is initially initialized -but `rhs` is uninitialized, `T`'s ['destructor] is called. If `*this` is -initially uninitialized but rhs is initialized, `T`'s ['converting constructor] -(from `U`) is called. -* [*Exception Safety:] In the event of an exception, the initialization state -of `*this` is unchanged and its value unspecified as far as optional is -concerned (it is up to `T`'s `operator=()`). If `*this` is initially -uninitialized and `T`'s converting constructor fails, `*this` is left properly -uninitialized. +* [*Effect:] +[table + [[][`*this` contains a value][`*this` does not contain a value]] + [[`rhs` contains a value][assigns `*rhs` to the contained value][initializes the contained value as if direct-initializing an object of type `T` with `*rhs`]] + [[`rhs` does not contain a value][destroys the contained value by calling `val->T::~T()`][no effect]] +] +* [*Returns:] `*this`. +* [*Postconditions:] `bool(rhs) == bool(*this)`. +* [*Exception Safety:] If any exception is thrown, the result of the expression `bool(*this)` remains unchanged. +If an exception is thrown during the call to `T`'s constructor, no effect. +If an exception is thrown during the call to `T`'s assignment, the state of its contained value is as defined by the exception safety guarantee of `T`'s copy assignment. * [*Example:] `` T v; @@ -727,21 +725,17 @@ __SPACE__ [: `template optional& optional::operator= ( optional&& rhs ) ;`] -* [*Effect:] Move-assigns another convertible optional to an optional. -* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and -its value is moved from the value of `rhs`; else -`*this` is uninitialized. -* [*Throws:] Whatever `T::operator=( U&& )` or `T::T( U&& )` throws. -* [*Notes:] If both `*this` and `rhs` are initially initialized, `T`'s -[' assignment operator] (from `U&&`) is used. If `*this` is initially initialized -but `rhs` is uninitialized, `T`'s ['destructor] is called. If `*this` is -initially uninitialized but `rhs` is initialized, `T`'s ['converting constructor] -(from `U&&`) is called. -* [*Exception Safety:] In the event of an exception, the initialization state -of `*this` is unchanged and its value unspecified as far as optional is -concerned (it is up to `T`'s `operator=()`). If `*this` is initially -uninitialized and `T`'s converting constructor fails, `*this` is left properly -uninitialized. +* [*Effect:] +[table + [[][`*this` contains a value][`*this` does not contain a value]] + [[`rhs` contains a value][assigns `std::move(*rhs)` to the contained value][initializes the contained value as if direct-initializing an object of type `T` with `std::move(*rhs)`]] + [[`rhs` does not contain a value][destroys the contained value by calling `val->T::~T()`][no effect]] +] +* [*Returns:] `*this`. +* [*Postconditions:] `bool(rhs) == bool(*this)`. +* [*Exception Safety:] If any exception is thrown, the result of the expression `bool(*this)` remains unchanged. +If an exception is thrown during the call to `T`'s constructor, no effect. +If an exception is thrown during the call to `T`'s assignment, the state of its contained value is as defined by the exception safety guarantee of `T`'s copy assignment. * [*Example:] `` T v; @@ -1256,10 +1250,11 @@ __SPACE__ * [*Requires:] Lvalues of type `T` shall be swappable and `T` shall be __MOVE_CONSTRUCTIBLE__. * [*Effects:] - * If `!*this && !rhs`, no effect, otherwise - * if `bool(*this) && !rhs`, initializes the contained value of `rhs` as if direct-initializing an object of type `T` with the expression `std::move(*(*this))`, followed by `val->T::~T()`, `*this` does not contain a value and `rhs` contains a value, otherwise - * if `!*this && bool(rhs)`, initializes the contained value of `*this` as if direct-initializing an object of type `T` with the expression `std::move(*rhs)`, followed by `rhs.val->T::~T()`, `*this` contains a value and `rhs` does not contain a value, otherwise - * (if `bool(*this) && bool(rhs)`) calls `swap(*(*this), *rhs)`. +[table + [[][`*this` contains a value][`*this` does not contain a value]] + [[`rhs` contains a value][calls `swap(*(*this), *rhs)`][initializes the contained value of `*this` as if direct-initializing an object of type `T` with the expression `std::move(*rhs)`, followed by `rhs.val->T::~T()`, `*this` contains a value and `rhs` does not contain a value]] + [[`rhs` does not contain a value][initializes the contained value of `rhs` as if direct-initializing an object of type `T` with the expression `std::move(*(*this))`, followed by `val->T::~T()`, `*this` does not contain a value and `rhs` contains a value][no effect]] +] * [*Postconditions:] The states of `x` and `y` interchanged. * [*Throws:] If both are initialized, whatever `swap(T&,T&)` throws. If only one is initialized, whatever `T::T ( T&& )` throws. diff --git a/doc/91_relnotes.qbk b/doc/91_relnotes.qbk index 3cffa97..ea400c7 100644 --- a/doc/91_relnotes.qbk +++ b/doc/91_relnotes.qbk @@ -17,6 +17,7 @@ * 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] +* It is no longer possible to assign `optional` to `optional` when `U` is not assignable or convertible to `T`. [heading Boost Release 1.57] diff --git a/doc/html/boost_optional/reference/detailed_semantics.html b/doc/html/boost_optional/reference/detailed_semantics.html index 2e017d2..8bff973 100644 --- a/doc/html/boost_optional/reference/detailed_semantics.html +++ b/doc/html/boost_optional/reference/detailed_semantics.html @@ -808,30 +808,74 @@ is CopyConstructible and CopyAssignable.
  • +

    Effects: -

      -
    • - If !*this - && !rhs no effect, otherwise -
    • -
    • - if bool(*this) - && !rhs, destroys the contained value - by calling val->T::~T(), otherwise -
    • -
    • - if !*this - && bool(rhs), initializes the contained value - as if direct-initializing an object of type T - with *rhs, - otherwise -
    • -
    • - (if bool(*this) - && bool(rhs)) assigns *rhs to the contained value. -
    • -
    -
  • +

    +
    +++++ + + + + + + + + + + + + + + + + + +
    + +

    + *this + contains a value +

    +
    +

    + *this + does not contain a value +

    +
    +

    + rhs contains + a value +

    +
    +

    + assigns *rhs + to the contained value +

    +
    +

    + initializes the contained value as if direct-initializing an + object of type T + with *rhs +

    +
    +

    + rhs does not + contain a value +

    +
    +

    + destroys the contained value by calling val->T::~T() +

    +
    +

    + no effect +

    +
    +
  • Returns: *this;
  • @@ -919,30 +963,73 @@ and MoveAssignable.
  • +

    Effects: -

      -
    • - If !*this - && !rhs no effect, otherwise -
    • -
    • - if bool(*this) - && !rhs, destroys the contained value - by calling val->T::~T(), otherwise -
    • -
    • - if !*this - && bool(rhs), initializes the contained value - as if direct-initializing an object of type T - with std::move(*rhs), - otherwise -
    • -
    • - (if bool(*this) - && bool(rhs)) assigns std::move(*rhs) to the contained value. -
    • -
    -
  • +

    +
    +++++ + + + + + + + + + + + + + + + + + +
    + +

    + *this + contains a value +

    +
    +

    + *this + does not contain a value +

    +
    +

    + rhs contains + a value +

    +
    +

    + assigns std::move(*rhs) to the contained value +

    +
    +

    + initializes the contained value as if direct-initializing an + object of type T + with std::move(*rhs) +

    +
    +

    + rhs does not + contain a value +

    +
    +

    + destroys the contained value by calling val->T::~T() +

    +
    +

    + no effect +

    +
    +
  • Returns: *this;
  • @@ -997,40 +1084,88 @@

    • - Effect: Assigns another convertible - optional to an optional. +

      + Effect: +

      +
      +++++ + + + + + + + + + + + + + + + + + +
      + +

      + *this + contains a value +

      +
      +

      + *this + does not contain a value +

      +
      +

      + rhs contains + a value +

      +
      +

      + assigns *rhs + to the contained value +

      +
      +

      + initializes the contained value as if direct-initializing an + object of type T + with *rhs +

      +
      +

      + rhs does not + contain a value +

      +
      +

      + destroys the contained value by calling val->T::~T() +

      +
      +

      + no effect +

      +
      +
    • +
    • + Returns: *this.
    • - Postconditions: If rhs - is initialized, *this - is initialized and its value is a copy of the value - of rhs converted - to type T; else *this - is uninitialized. + Postconditions: bool(rhs) == bool(*this).
    • - Throws: Whatever T::operator=( U const& ) or T::T( U const& ) throws. -
    • -
    • - Notes: If both *this and rhs are initially initialized, - T's assignment - operator (from U) - is used. If *this - is initially initialized but rhs - is uninitialized, T's - destructor is called. If *this is initially uninitialized but rhs - is initialized, T's - converting constructor (from U) - is called. -
    • -
    • - Exception Safety: In the event of an - exception, the initialization state of *this is unchanged and its value unspecified - as far as optional is concerned (it is up to T's - operator=()). - If *this - is initially uninitialized and T's - converting constructor fails, *this is left properly uninitialized. + Exception Safety: If any exception is + thrown, the result of the expression bool(*this) remains unchanged. If an exception is + thrown during the call to T's + constructor, no effect. If an exception is thrown during the call to + T's assignment, the state + of its contained value is as defined by the exception safety guarantee + of T's copy assignment.
    • Example: @@ -1053,36 +1188,87 @@

    • - Effect: Move-assigns another convertible - optional to an optional. +

      + Effect: +

      +
      +++++ + + + + + + + + + + + + + + + + + +
      + +

      + *this + contains a value +

      +
      +

      + *this + does not contain a value +

      +
      +

      + rhs contains + a value +

      +
      +

      + assigns std::move(*rhs) to the contained value +

      +
      +

      + initializes the contained value as if direct-initializing an + object of type T + with std::move(*rhs) +

      +
      +

      + rhs does not + contain a value +

      +
      +

      + destroys the contained value by calling val->T::~T() +

      +
      +

      + no effect +

      +
      +
    • +
    • + Returns: *this.
    • - Postconditions: If rhs - is initialized, *this - is initialized and its value is moved from the value of rhs; else *this is uninitialized. + Postconditions: bool(rhs) == bool(*this).
    • - Throws: Whatever T::operator=( U&& ) - or T::T( U&& - ) throws. -
    • -
    • - Notes: If both *this and rhs - are initially initialized, T's - assignment operator (from U&&) is used. If *this - is initially initialized but rhs - is uninitialized, T's - destructor is called. If *this is initially uninitialized but rhs is initialized, T's - converting constructor (from U&&) is called. -
    • -
    • - Exception Safety: In the event of an - exception, the initialization state of *this is unchanged and its value unspecified - as far as optional is concerned (it is up to T's - operator=()). - If *this - is initially uninitialized and T's - converting constructor fails, *this is left properly uninitialized. + Exception Safety: If any exception is + thrown, the result of the expression bool(*this) remains unchanged. If an exception is + thrown during the call to T's + constructor, no effect. If an exception is thrown during the call to + T's assignment, the state + of its contained value is as defined by the exception safety guarantee + of T's copy assignment.
    • Example: @@ -2019,35 +2205,81 @@ Requires: Lvalues of type T shall be swappable and T shall be MoveConstructible.
    • +

      Effects: -

        -
      • - If !*this - && !rhs, no effect, otherwise -
      • -
      • - if bool(*this) - && !rhs, initializes the contained - value of rhs as - if direct-initializing an object of type T - with the expression std::move(*(*this)), followed by val->T::~T(), *this does not contain a value and - rhs contains a - value, otherwise -
      • -
      • - if !*this - && bool(rhs), initializes the contained value - of *this - as if direct-initializing an object of type T - with the expression std::move(*rhs), followed by rhs.val->T::~T(), *this contains a value and rhs does not contain a value, - otherwise -
      • -
      • - (if bool(*this) - && bool(rhs)) calls swap(*(*this), *rhs). -
      • -
      -
    • +

      +
      +++++ + + + + + + + + + + + + + + + + + +
      + +

      + *this + contains a value +

      +
      +

      + *this + does not contain a value +

      +
      +

      + rhs contains + a value +

      +
      +

      + calls swap(*(*this), *rhs) +

      +
      +

      + initializes the contained value of *this as if direct-initializing + an object of type T + with the expression std::move(*rhs), followed by rhs.val->T::~T(), + *this + contains a value and rhs + does not contain a value +

      +
      +

      + rhs does not + contain a value +

      +
      +

      + initializes the contained value of rhs + as if direct-initializing an object of type T + with the expression std::move(*(*this)), followed by val->T::~T(), + *this + does not contain a value and rhs + contains a value +

      +
      +

      + no effect +

      +
      +
    • Postconditions: The states of x and y interchanged. diff --git a/doc/html/boost_optional/relnotes.html b/doc/html/boost_optional/relnotes.html index 02fcd41..1d476e3 100644 --- a/doc/html/boost_optional/relnotes.html +++ b/doc/html/boost_optional/relnotes.html @@ -52,6 +52,10 @@ This can be used to work around Trac #10399
    • +
    • + It is no longer possible to assign optional<U> to optional<T> when U + is not assignable or convertible to T. +

    diff --git a/doc/html/index.html b/doc/html/index.html index 3abdc22..0c30992 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -138,7 +138,7 @@ - +

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

    Last revised: March 06, 2015 at 18:13:34 GMT


    diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index f8d631d..56f5096 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -188,7 +188,7 @@ struct types_when_is_ref template void prevent_binding_rvalue_ref_to_optional_lvalue_ref() { -#ifndef BOOST_OPTIONAL_ALLOW_BINDING_TO_RVALUES +#ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES BOOST_STATIC_ASSERT_MSG( !boost::is_lvalue_reference::value || !boost::is_rvalue_reference::value, "binding rvalue references to optional lvalue references is disallowed"); @@ -371,13 +371,22 @@ class optional_base : public optional_tag if (is_initialized()) { if ( rhs.is_initialized() ) - assign_value(static_cast(rhs.get()), is_reference_predicate() ); +#ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES + assign_value(rhs.get(), is_reference_predicate() ); +#else + assign_value(static_cast(rhs.get()), is_reference_predicate() ); +#endif + else destroy(); } else { if ( rhs.is_initialized() ) +#ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES + construct(rhs.get()); +#else construct(static_cast(rhs.get())); +#endif } } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9db0c01..54535b7 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -56,5 +56,6 @@ import testing ; [ compile-fail optional_test_fail_explicit_convert_in_value_or.cpp ] [ compile-fail optional_test_fail_explicit_convert_in_value_or_call.cpp ] [ compile-fail optional_test_fail_io_without_io.cpp ] + [ compile-fail optional_test_fail_convert_assign_of_enums.cpp ] ; } diff --git a/test/optional_test_fail_convert_assign_of_enums.cpp b/test/optional_test_fail_convert_assign_of_enums.cpp new file mode 100644 index 0000000..184e282 --- /dev/null +++ b/test/optional_test_fail_convert_assign_of_enums.cpp @@ -0,0 +1,27 @@ +// 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 + +#include +#include "boost/optional.hpp" + +// THIS TEST SHOULD FAIL TO COMPILE + +enum E1 {e1}; +enum E2 {e2}; + +void test_converitng_assignment_of_different_enums() +{ + boost::optional o2(e2); + boost::optional o1; + o1 = o2; +} + +int main() {}