From fdc98d17ca4360e921d3384a4d7210b74646bbd7 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Fri, 6 Jun 2014 23:24:43 +0200 Subject: [PATCH 1/5] Added limited emplace() for older compilers --- doc/00_optional.qbk | 2 +- doc/18_type_requirements.qbk | 36 +++- doc/20_reference.qbk | 10 +- .../quick_start/optional_data_members.html | 16 +- .../reference/detailed_semantics.html | 15 +- .../tutorial/type_requirements.html | 79 ++++++-- doc/html/index.html | 2 +- doc/html/optional/reference.html | 184 ++++++++++++++++++ doc/html/optional/tutorial.html | 149 ++++++++++++++ include/boost/optional/optional.hpp | 43 ++++ test/Jamfile.v2 | 1 + test/optional_test_minimum_requirements.cpp | 104 ++++++++++ 12 files changed, 612 insertions(+), 29 deletions(-) create mode 100644 doc/html/optional/reference.html create mode 100644 doc/html/optional/tutorial.html create mode 100644 test/optional_test_minimum_requirements.cpp diff --git a/doc/00_optional.qbk b/doc/00_optional.qbk index 9cceee1..96209ef 100644 --- a/doc/00_optional.qbk +++ b/doc/00_optional.qbk @@ -36,7 +36,7 @@ Distributed under the Boost Software License, Version 1.0. [/ Other web resources ] [def __HASKELL__ [@http://www.haskell.org/ Haskell]] -[def __SGI_DEFAULT_CONSTRUCTIBLE__ [@http://www.sgi.com/tech/stl/DefaultConstructible.html Default Constructible]] +[def __SGI_DEFAULT_CONSTRUCTIBLE__ [@http://www.sgi.com/tech/stl/DefaultConstructible.html `DefaultConstructible`]] [/ Icons ] diff --git a/doc/18_type_requirements.qbk b/doc/18_type_requirements.qbk index b8fd405..6faae48 100644 --- a/doc/18_type_requirements.qbk +++ b/doc/18_type_requirements.qbk @@ -1,10 +1,38 @@  [section Type requirements] -At the very minimum for `optional` to work with a minimum interface it is required that `T` has a publicly accessible no-throw destructor. In that case you need to initialize the optional object with function `emplace()` or use [*InPlaceFactories]. -Additionally, if `T` is `Moveable`, `optional` is also `Moveable` and can be easily initialized from an rvalue of type `T` and be passed by value. -Additionally, if `T` is `Copyable`, `optional` is also `Copyable` and can be easily initialized from an lvalue of type `T`. +The very minimum requirement of `optional` is that `T` is a complete type and that it has a publicly accessible destructor. `T` doesn't even need to be constructible. You can use a very minimum interface: -`T` [_is not] required to be __SGI_DEFAULT_CONSTRUCTIBLE__. + optional o; // uninitialized + assert(o == none); // check if initialized + assert(!o); // + o.value(); // always throws + +But this is practically useless. In order for `optional` to be able to do anything useful and offer all the spectrum of ways of accessing the contained value, `T` needs to have at least one accessible constructor. In that case you need to initialize the optional object with function `emplace()`, or if your compiler does not support it, resort to [link boost_optional.tutorial.in_place_factories In-Place Factories]: + + optional o; + o.emplace("T", "ctor", "params"); + +If `T` is `MoveConstructible`, `optional` is also `MoveConstructible` and can be easily initialized from an rvalue of type `T` and be passed by value: + + optional o = make_T(); + optional p = optional(); + +If `T` is `CopyConstructible`, `optional` is also `CopyConstructible` and can be easily initialized from an lvalue of type `T`: + + T v = make_T(); + optional o = v; + optional p = o; + +If `T` is not `MoveAssignable`, it is still possible to reset the value of `optional` using function `emplace()`: + + optional o = make_T(); + o.emplace(make_another_T()); + +If `T` is `Moveable` (both `MoveConstructible` and `MoveAssignable`) then `optional` is also `Moveable` and additionally can be constructed and assigned from an rvalue of type `T`. + +Similarly, if `T` is `Copyable` (both `CopyConstructible` and `CopyAssignable`) then `optional` is also `Copyable` and additionally can be constructed and assigned from an lvalue of type `T`. + +`T` ['is not] required to be __SGI_DEFAULT_CONSTRUCTIBLE__. [endsect] diff --git a/doc/20_reference.qbk b/doc/20_reference.qbk index 966f8ec..82cd932 100644 --- a/doc/20_reference.qbk +++ b/doc/20_reference.qbk @@ -761,8 +761,16 @@ __SPACE__ of type `T` with `std::forward(args)...`. * [*Postconditions: ] `*this` is [_initialized]. * [*Throws:] Whatever the selected `T`'s constructor throws. -* [*Notes:] `T` need not be `MoveConstructible` or `MoveAssignable`. +* [*Notes:] `T` need not be `MoveConstructible` or `MoveAssignable`. On compilers that do not support variadic templates, the signature falls back to single-argument: `template void emplace(Arg&& arg)`. On compilers that do not support rvalue references, the signature falls back to two overloads: taking `const` and non-`const` lvalue reference. * [*Exception Safety:] If an exception is thrown during the initialization of `T`, `*this` is ['uninitialized]. +* [*Example:] +`` +T v; +optional opt; +opt.emplace(0); // create in-place using ctor T(int) +opt.emplace(); // destroy previous and default-construct another T +opt.emplace(v); // destroy and copy-construct in-place (no assignment called) +`` __SPACE__ diff --git a/doc/html/boost_optional/quick_start/optional_data_members.html b/doc/html/boost_optional/quick_start/optional_data_members.html index fe7fd78..505f0ce 100644 --- a/doc/html/boost_optional/quick_start/optional_data_members.html +++ b/doc/html/boost_optional/quick_start/optional_data_members.html @@ -53,13 +53,15 @@ optional's default constructor creates an uninitialized optional. No call to Resource's default constructor is attempted. Resource - doesn't have to be Default - Constructible. In function getResource - we first check if resource_ - is initialized. This time we do not use the contextual conversion to bool, but a comparison with boost::none. These two ways are equivalent. Function - emplace initializes the optional - in-place by perfect-forwarding the arguments to the constructor of Resource. No copy- or move-construction - is involved here. Resource + doesn't have to be DefaultConstructible. In function + getResource we first check + if resource_ is initialized. + This time we do not use the contextual conversion to bool, + but a comparison with boost::none. + These two ways are equivalent. Function emplace + initializes the optional in-place by perfect-forwarding the arguments to + the constructor of Resource. + No copy- or move-construction is involved here. Resource doesn't even have to be MoveConstructible.

diff --git a/doc/html/boost_optional/reference/detailed_semantics.html b/doc/html/boost_optional/reference/detailed_semantics.html index 2bf9023..5d71e1d 100644 --- a/doc/html/boost_optional/reference/detailed_semantics.html +++ b/doc/html/boost_optional/reference/detailed_semantics.html @@ -1094,7 +1094,11 @@
  • Notes: T need not be MoveConstructible - or MoveAssignable. + or MoveAssignable. On + compilers that do not support variadic templates, the signature falls + back to single-argument: template<class Arg> void emplace(Arg&& arg). On compilers that do not support rvalue + references, the signature falls back to two overloads: taking const and non-const + lvalue reference.
  • Exception Safety: If an exception is @@ -1102,6 +1106,15 @@ *this is uninitialized.
  • +
  • + Example: +
    T v;
    +optional<const T> opt;
    +opt.emplace(0);  // create in-place using ctor T(int)
    +opt.emplace();   // destroy previous and default-construct another T
    +opt.emplace(v);  // destroy and copy-construct in-place (no assignment called)
    +
    +
  • space diff --git a/doc/html/boost_optional/tutorial/type_requirements.html b/doc/html/boost_optional/tutorial/type_requirements.html index f8501dd..775e7bb 100644 --- a/doc/html/boost_optional/tutorial/type_requirements.html +++ b/doc/html/boost_optional/tutorial/type_requirements.html @@ -27,22 +27,73 @@ Type requirements

    - At the very minimum for optional<T> - to work with a minimum interface it is required that T - has a publicly accessible no-throw destructor. In that case you need to initialize - the optional object with function emplace() or use InPlaceFactories. - Additionally, if T is Moveable, optional<T> - is also Moveable and can - be easily initialized from an rvalue of type T - and be passed by value. Additionally, if T - is Copyable, optional<T> is - also Copyable and can be - easily initialized from an lvalue of type T. + The very minimum requirement of optional<T> + is that T is a complete type + and that it has a publicly accessible destructor. T + doesn't even need to be constructible. You can use a very minimum interface: +

    +
    optional<T> o;     // uninitialized
    +assert(o == none); // check if initialized
    +assert(!o);        //
    +o.value();         // always throws
    +
    +

    + But this is practically useless. In order for optional<T> + to be able to do anything useful and offer all the spectrum of ways of accessing + the contained value, T needs + to have at least one accessible constructor. In that case you need to initialize + the optional object with function emplace(), or if your compiler does not support it, + resort to In-Place + Factories: +

    +
    optional<T> o;
    +o.emplace("T", "ctor", "params");
    +
    +

    + If T is MoveConstructible, + optional<T> is + also MoveConstructible and + can be easily initialized from an rvalue of type T + and be passed by value: +

    +
    optional<T> o = make_T();
    +optional<T> p = optional<T>();
    +
    +

    + If T is CopyConstructible, + optional<T> is + also CopyConstructible and + can be easily initialized from an lvalue of type T: +

    +
    T v = make_T();
    +optional<T> o = v;
    +optional<T> p = o;
    +
    +

    + If T is not MoveAssignable, it is still possible to + reset the value of optional<T> + using function emplace(): +

    +
    optional<const T> o = make_T();
    +o.emplace(make_another_T());
    +
    +

    + If T is Moveable + (both MoveConstructible and + MoveAssignable) then optional<T> is + also Moveable and additionally + can be constructed and assigned from an rvalue of type T.

    - T is - not required to be Default - Constructible. + Similarly, if T is Copyable (both CopyConstructible + and CopyAssignable) then + optional<T> is + also Copyable and additionally + can be constructed and assigned from an lvalue of type T. +

    +

    + T is not + required to be DefaultConstructible.

    diff --git a/doc/html/index.html b/doc/html/index.html index 30310e9..f981d82 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -129,7 +129,7 @@
    - +

    Last revised: June 05, 2014 at 22:46:34 GMT

    Last revised: June 06, 2014 at 21:22:06 GMT


    diff --git a/doc/html/optional/reference.html b/doc/html/optional/reference.html new file mode 100644 index 0000000..a1a6d0e --- /dev/null +++ b/doc/html/optional/reference.html @@ -0,0 +1,184 @@ + + + +Reference + + + + + + + + + + + + + + + +
    Boost C++ LibrariesHomeLibrariesPeopleFAQMore
    +
    +
    +PrevUpHomeNext +
    +
    + + +
    + +
    // In Header: <boost/optional/optional.hpp>
    +
    +namespace boost {
    +
    +template<class T>
    +class optional
    +{
    +    public :
    +
    +    // (If T is of reference type, the parameters and results by reference are by value)
    +
    +    optional () noexcept ; R
    +
    +    optional ( none_t ) noexcept ; R
    +
    +    optional ( T const& v ) ; R
    +
    +    optional ( T&& v ) ; R
    +
    +    // [new in 1.34]
    +    optional ( bool condition, T const& v ) ; R
    +
    +    optional ( optional const& rhs ) ; R
    +
    +    optional ( optional&& rhs ) noexcept(see below) ; R
    +
    +    template<class U> explicit optional ( optional<U> const& rhs ) ; R
    +
    +    template<class U> explicit optional ( optional<U>&& rhs ) ; R
    +
    +    template<class InPlaceFactory> explicit optional ( InPlaceFactory const& f ) ; R
    +
    +    template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ; R
    +
    +    optional& operator = ( none_t ) noexcept ; R
    +
    +    optional& operator = ( T const& v ) ; R
    +
    +    optional& operator = ( T&& v ) ; R
    +
    +    optional& operator = ( optional const& rhs ) ; R
    +
    +    optional& operator = ( optional&& rhs ) noexcept(see below) ; R
    +
    +    template<class U> optional& operator = ( optional<U> const& rhs ) ; R
    +
    +    template<class U> optional& operator = ( optional<U>&& rhs ) ; R
    +
    +    template<class... Args> void emplace ( Args...&& args ) ; R
    +
    +    template<class InPlaceFactory> optional& operator = ( InPlaceFactory const& f ) ; R
    +
    +    template<class TypedInPlaceFactory> optional& operator = ( TypedInPlaceFactory const& f ) ; R
    +
    +    T const& get() const ; R
    +    T&       get() ; R
    +
    +    T const* operator ->() const ; R
    +    T*       operator ->() ; R
    +
    +    T const& operator *() const& ; R
    +    T&       operator *() &; R
    +    T&&      operator *() &&; R
    +
    +    T const& value() const& ; R
    +    T&       value() & ; R
    +    T&&      value() && ; R
    +
    +    template<class U> T value_or( U && v ) const& ; R
    +    template<class U> T value_or( U && v ) && ; R
    +
    +    T const* get_ptr() const ; R
    +    T*       get_ptr() ; R
    +
    +    explicit operator bool() const ; R
    +
    +    bool operator!() const noexcept ; R
    +
    +    // deprecated methods
    +
    +    // (deprecated)
    +    void reset() noexcept ; R
    +
    +    // (deprecated)
    +    void reset ( T const& ) ; R
    +
    +    // (deprecated)
    +    bool is_initialized() const ; R
    +
    +    // (deprecated)
    +    T const& get_value_or( T const& default ) const ; R
    +};
    +
    +template<class T> inline bool operator == ( optional<T> const& x, optional<T> const& y ) ; R
    +
    +template<class T> inline bool operator != ( optional<T> const& x, optional<T> const& y ) ; R
    +
    +template<class T> inline bool operator <  ( optional<T> const& x, optional<T> const& y ) ; R
    +
    +template<class T> inline bool operator >  ( optional<T> const& x, optional<T> const& y ) ; R
    +
    +template<class T> inline bool operator <= ( optional<T> const& x, optional<T> const& y ) ; R
    +
    +template<class T> inline bool operator >= ( optional<T> const& x, optional<T> const& y ) ; R
    +
    +template<class T> inline bool operator == ( optional<T> const& x, none_t ) noexcept ; R
    +
    +template<class T> inline bool operator != ( optional<T> const& x, none_t ) noexcept ; R
    +
    +template<class T> inline optional<T> make_optional ( T const& v ) ; R
    +
    +template<class T> inline optional<T> make_optional ( bool condition, T const& v ) ; R
    +
    +template<class T> inline T const& get_optional_value_or ( optional<T> const& opt, T const& default ) ; R
    +
    +template<class T> inline T const& get ( optional<T> const& opt ) ; R
    +
    +template<class T> inline T& get ( optional<T> & opt ) ; R
    +
    +template<class T> inline T const* get ( optional<T> const* opt ) ; R
    +
    +template<class T> inline T* get ( optional<T>* opt ) ; R
    +
    +template<class T> inline T const* get_pointer ( optional<T> const& opt ) ; R
    +
    +template<class T> inline T* get_pointer ( optional<T> & opt ) ; R
    +
    +template<class T> inline void swap( optional<T>& x, optional<T>& y ) ; R
    +
    +} // namespace boost
    +
    +
    +
    + + + +
    +
    +
    +PrevUpHomeNext +
    + + diff --git a/doc/html/optional/tutorial.html b/doc/html/optional/tutorial.html new file mode 100644 index 0000000..f09045f --- /dev/null +++ b/doc/html/optional/tutorial.html @@ -0,0 +1,149 @@ + + + +Tutorial + + + + + + + + + + + + + + + +
    Boost C++ LibrariesHomeLibrariesPeopleFAQMore
    +
    +
    +PrevUpHomeNext +
    +
    + + +
    + +

    + Consider these functions which should return a value but which might not + have a value to return: +

    +
      +
    • + (A) double sqrt(double n ); +
    • +
    • + (B) char get_async_input(); +
    • +
    • + (C) point polygon::get_any_point_effectively_inside(); +
    • +
    +

    + There are different approaches to the issue of not having a value to return. +

    +

    + A typical approach is to consider the existence of a valid return value as + a postcondition, so that if the function cannot compute the value to return, + it has either undefined behavior (and can use assert in a debug build) or + uses a runtime check and throws an exception if the postcondition is violated. + This is a reasonable choice for example, for function (A), because the lack + of a proper return value is directly related to an invalid parameter (out + of domain argument), so it is appropriate to require the callee to supply + only parameters in a valid domain for execution to continue normally. +

    +

    + However, function (B), because of its asynchronous nature, does not fail + just because it can't find a value to return; so it is incorrect to consider + such a situation an error and assert or throw an exception. This function + must return, and somehow, must tell the callee that it is not returning a + meaningful value. +

    +

    + A similar situation occurs with function (C): it is conceptually an error + to ask a null-area polygon to return a point inside + itself, but in many applications, it is just impractical for performance + reasons to treat this as an error (because detecting that the polygon has + no area might be too expensive to be required to be tested previously), and + either an arbitrary point (typically at infinity) is returned, or some efficient + way to tell the callee that there is no such point is used. +

    +

    + There are various mechanisms to let functions communicate that the returned + value is not valid. One such mechanism, which is quite common since it has + zero or negligible overhead, is to use a special value which is reserved + to communicate this. Classical examples of such special values are EOF, string::npos, + points at infinity, etc... +

    +

    + When those values exist, i.e. the return type can hold all meaningful values + plus the signal value, this mechanism + is quite appropriate and well known. Unfortunately, there are cases when + such values do not exist. In these cases, the usual alternative is either + to use a wider type, such as int + in place of char; or a compound + type, such as std::pair<point,bool>. +

    +

    + Returning a std::pair<T,bool>, thus attaching a boolean flag to the + result which indicates if the result is meaningful, has the advantage that + can be turned into a consistent idiom since the first element of the pair + can be whatever the function would conceptually return. For example, the + last two functions could have the following interface: +

    +
    std::pair<char,bool> get_async_input();
    +std::pair<point,bool> polygon::get_any_point_effectively_inside();
    +
    +

    + These functions use a consistent interface for dealing with possibly nonexistent + results: +

    +
    std::pair<point,bool> p = poly.get_any_point_effectively_inside();
    +if ( p.second )
    +    flood_fill(p.first);
    +
    +

    + However, not only is this quite a burden syntactically, it is also error + prone since the user can easily use the function result (first element of + the pair) without ever checking if it has a valid value. +

    +

    + Clearly, we need a better idiom. +

    +
    +
    + + + +
    +
    +
    +PrevUpHomeNext +
    + + diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 6e3b160..a9763a5 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -475,6 +475,7 @@ class optional_base : public optional_tag } #endif + #if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) // Constructs in-place // upon exception *this is always uninitialized @@ -485,6 +486,30 @@ 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) + template + void emplace_assign ( Arg&& arg ) + { + destroy(); + ::new (m_storage.address()) internal_type( boost::forward(arg) ); + m_initialized = true ; + } +#else + template + void emplace_assign ( const Arg& arg ) + { + destroy(); + ::new (m_storage.address()) internal_type( arg ); + m_initialized = true ; + } + + template + void emplace_assign ( Arg& arg ) + { + destroy(); + ::new (m_storage.address()) internal_type( arg ); + m_initialized = true ; + } #endif #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT @@ -933,6 +958,24 @@ class optional : public optional_detail::optional_base { this->emplace_assign( boost::forward(args)... ); } +#elif (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) + template + void emplace ( Arg&& arg ) + { + this->emplace_assign( boost::forward(arg) ); + } +#else + template + void emplace ( const Arg& arg ) + { + this->emplace_assign( arg ); + } + + template + void emplace ( Arg& arg ) + { + this->emplace_assign( arg ); + } #endif void swap( optional & arg ) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 48ddf3f..9d5e856 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -25,6 +25,7 @@ import testing ; [ run optional_test_equals_none.cpp ] [ run optional_test_value_access.cpp ] [ run optional_test_emplace.cpp ] + [ run optional_test_minimum_requirements.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_minimum_requirements.cpp b/test/optional_test_minimum_requirements.cpp new file mode 100644 index 0000000..5649d69 --- /dev/null +++ b/test/optional_test_minimum_requirements.cpp @@ -0,0 +1,104 @@ +// 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 +// +// Revisions: +// +#include +#include +#include + +#define BOOST_ENABLE_ASSERT_HANDLER + +#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_fwd.hpp" // For mpl::true_ and mpl::false_ +#include "boost/static_assert.hpp" + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/none.hpp" + +#include "boost/test/minimal.hpp" + +#include "optional_test_common.cpp" + +class NonConstructible +{ +private: + NonConstructible(); + NonConstructible(NonConstructible const&); +#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) + NonConstructible(NonConstructible &&); +#endif +}; + +void test_non_constructible() +{ + optional o; + BOOST_CHECK(!o); + BOOST_CHECK(o == boost::none); + try { + o.value(); + BOOST_CHECK(false); + } + catch(...) { + BOOST_CHECK(true); + } +} + +class Guard +{ +public: + explicit Guard(int) {} +private: + Guard(); + Guard(Guard const&); +#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) + Guard(Guard &&); +#endif +}; + +void test_guard() +{ + optional o; + o.emplace(1); + BOOST_CHECK(o); +} + +void test_non_assignable() +{ + optional o; + o.emplace("cat"); + BOOST_CHECK(o); + BOOST_CHECK(*o == "cat"); +} + +int test_main( int, char* [] ) +{ + try + { + test_non_constructible(); + test_guard(); + test_non_assignable(); + } + catch ( ... ) + { + BOOST_ERROR("Unexpected Exception caught!"); + } + + return 0; +} + + From a4e507077ebeb0f6469247ee1f61ec36155088a4 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Fri, 6 Jun 2014 23:40:45 +0200 Subject: [PATCH 2/5] More tests on emplace() --- test/optional_test_emplace.cpp | 76 +++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/test/optional_test_emplace.cpp b/test/optional_test_emplace.cpp index 2bc761a..b55c1eb 100644 --- a/test/optional_test_emplace.cpp +++ b/test/optional_test_emplace.cpp @@ -58,21 +58,6 @@ private: void operator=(Guard const&); }; -struct Thrower -{ - Thrower(bool throw_) { if (throw_) throw int(); } - -private: - Thrower(Thrower const&); - Thrower(Thrower&&); -}; - -struct ThrowOnMove -{ - ThrowOnMove(ThrowOnMove&&) { throw int(); } - ThrowOnMove(ThrowOnMove const&) { throw int(); } - ThrowOnMove(int){} -}; void test_emplace() { @@ -115,6 +100,44 @@ void test_emplace() BOOST_CHECK(7 == o->which_ctor); } + +#endif + +#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) + + +struct ThrowOnMove +{ + ThrowOnMove(ThrowOnMove&&) { throw int(); } + ThrowOnMove(ThrowOnMove const&) { throw int(); } + ThrowOnMove(int){} +}; + + +void test_no_moves_on_emplacement() +{ + try { + optional o; + o.emplace(1); + BOOST_CHECK(o); + } + catch (...) { + BOOST_CHECK(false); + } +} +#endif + +struct Thrower +{ + Thrower(bool throw_) { if (throw_) throw int(); } + +private: + Thrower(Thrower const&); +#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) + Thrower(Thrower&&); +#endif +}; + void test_clear_on_throw() { optional ot; @@ -133,30 +156,27 @@ void test_clear_on_throw() } } -void test_no_moves_on_emplacement() +void test_no_assignment_on_emplacement() { - try { - optional o; - o.emplace(1); - BOOST_CHECK(o); - } - catch (...) { - BOOST_CHECK(false); - } + optional os; + BOOST_CHECK(!os); + os.emplace("wow"); + BOOST_CHECK(os); + BOOST_CHECK(*os == "wow"); } -#endif - - int test_main( int, char* [] ) { try { #if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) test_emplace(); - test_clear_on_throw(); +#endif +#if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) test_no_moves_on_emplacement(); #endif + test_clear_on_throw(); + test_no_assignment_on_emplacement(); } catch ( ... ) { From d25b0cfd59c9705901f99543e5e92d04c558403d Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Fri, 6 Jun 2014 23:52:29 +0200 Subject: [PATCH 3/5] improved example in tutorial --- doc/01_quick_start.qbk | 4 ++-- .../boost_optional/quick_start/optional_data_members.html | 4 ++-- doc/html/index.html | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/01_quick_start.qbk b/doc/01_quick_start.qbk index 2b642df..fee59c5 100644 --- a/doc/01_quick_start.qbk +++ b/doc/01_quick_start.qbk @@ -88,12 +88,12 @@ Suppose we want to implement a ['lazy load] optimization. This is because we do class Widget { - boost::optional resource_; + mutable boost::optional resource_; public: Widget() {} - Resource& getResource() // not thread-safe + const Resource& getResource() const // not thread-safe { if (resource_ == boost::none) resource_.emplace("resource", "arguments"); diff --git a/doc/html/boost_optional/quick_start/optional_data_members.html b/doc/html/boost_optional/quick_start/optional_data_members.html index 505f0ce..abb5589 100644 --- a/doc/html/boost_optional/quick_start/optional_data_members.html +++ b/doc/html/boost_optional/quick_start/optional_data_members.html @@ -35,12 +35,12 @@

    class Widget
     {
    -  boost::optional<Resource> resource_;
    +  mutable boost::optional<const Resource> resource_;
     
     public:
       Widget() {}
     
    -  Resource& getResource() // not thread-safe
    +  const Resource& getResource() const // not thread-safe
       {
         if (resource_ == boost::none)
             resource_.emplace("resource", "arguments");
    diff --git a/doc/html/index.html b/doc/html/index.html
    index f981d82..297e7be 100644
    --- a/doc/html/index.html
    +++ b/doc/html/index.html
    @@ -129,7 +129,7 @@
     
    - +

    Last revised: June 06, 2014 at 21:22:06 GMT

    Last revised: June 06, 2014 at 21:50:26 GMT


    From befd3970d7b3b7dae49afeb5bb7630f599ed5241 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sun, 8 Jun 2014 16:23:35 +0200 Subject: [PATCH 4/5] docs -- expanded tutprial section --- doc/00_optional.qbk | 9 +- doc/01_quick_start.qbk | 4 +- doc/{12_motivation.qbk => 10_motivation.qbk} | 0 ...{13_development.qbk => 11_development.qbk} | 0 doc/12_when_to_use.qbk | 37 +++++ doc/13_relational_operators.qbk | 35 +++++ ...sing_unnecessary_default_construction.html | 8 +- .../quick_start/storage_in_containers.html | 11 +- .../design_overview/the_interface.html | 6 +- .../tutorial/optional_references.html | 6 +- .../tutorial/relational_operators.html | 108 +++++++++++++ .../tutorial/when_to_use_optional.html | 142 ++++++++++++++++++ doc/html/index.html | 6 +- doc/html/optional/tutorial.html | 4 + 14 files changed, 353 insertions(+), 23 deletions(-) rename doc/{12_motivation.qbk => 10_motivation.qbk} (100%) rename doc/{13_development.qbk => 11_development.qbk} (100%) create mode 100644 doc/12_when_to_use.qbk create mode 100644 doc/13_relational_operators.qbk create mode 100644 doc/html/boost_optional/tutorial/relational_operators.html create mode 100644 doc/html/boost_optional/tutorial/when_to_use_optional.html diff --git a/doc/00_optional.qbk b/doc/00_optional.qbk index 96209ef..fb5d584 100644 --- a/doc/00_optional.qbk +++ b/doc/00_optional.qbk @@ -23,6 +23,7 @@ Distributed under the Boost Software License, Version 1.0. [/ Cited Boost resources ] [def __BOOST_VARIANT__ [@../../../variant/index.html Boost.Variant]] +[def __BOOST_TUPLE__ [@../../../tuple/index.html Boost.Tuple]] [def __BOOST_TRIBOOL__ [@../../../../doc/html/tribool.html boost::tribool]] [def __OPTIONAL_POINTEE__ [@../../../utility/OptionalPointee.html OptionalPointee]] @@ -37,6 +38,8 @@ Distributed under the Boost Software License, Version 1.0. [def __HASKELL__ [@http://www.haskell.org/ Haskell]] [def __SGI_DEFAULT_CONSTRUCTIBLE__ [@http://www.sgi.com/tech/stl/DefaultConstructible.html `DefaultConstructible`]] +[def __SGI_LESS_THAN_COMPARABLE__ [@http://www.sgi.com/tech/stl/LessThanComparable.html `LessThanComparable`]] +[def __SGI_EQUALITY_COMPARABLE__ [@http://www.sgi.com/tech/stl/EqualityComparable.html `EqualityComparable`]] [/ Icons ] @@ -71,8 +74,10 @@ This is how you solve it with `boost::optional`: [include 01_quick_start.qbk] [section Tutorial] -[include 12_motivation.qbk] -[include 13_development.qbk] +[include 10_motivation.qbk] +[include 11_development.qbk] +[include 12_when_to_use.qbk] +[include 13_relational_operators.qbk] [include 14_optional_references.qbk] [include 15_in_place_factories.qbk] [include 16_optional_bool.qbk] diff --git a/doc/01_quick_start.qbk b/doc/01_quick_start.qbk index fee59c5..10d55e6 100644 --- a/doc/01_quick_start.qbk +++ b/doc/01_quick_start.qbk @@ -119,7 +119,7 @@ In other place we want to use the result of `getPeriod`, but want the two dates Date begin, end; // Error: no default ctor! boost::tie(begin, end) = getPeriod(); -The second line works already, this is the capability of Boost.Tuple library, but the first line won't work. We could set some invented initial dates, but it is confusing and may be an unacceptable cost, given that these values will be overwritten in the next line anyway. This is where `optional` can help: +The second line works already, this is the capability of __BOOST_TUPLE__ library, but the first line won't work. We could set some invented initial dates, but it is confusing and may be an unacceptable cost, given that these values will be overwritten in the next line anyway. This is where `optional` can help: boost::optional begin, end; boost::tie(begin, end) = getPeriod(); @@ -138,7 +138,7 @@ Suppose you want to ask users to choose some number (an `int`). One of the valid ++choices[choice]; } -This works because `optional` is `LessThanComparable` whenever `T` is `LessThanComparable`. In this case the state of being uninitialized is treated as a yet another value of `T`, which is compared less than any value of `T`. So the set of values that type `optional` can assume is {`boost::none`, -2147483648, -2147483647, ..., -1, 0, 1, ..., 2147483647} (assuming a 32-bit `int`). +This works because `optional` is __SGI_LESS_THAN_COMPARABLE__ whenever `T` is __SGI_LESS_THAN_COMPARABLE__. In this case the state of being uninitialized is treated as a yet another value of `T`, which is compared less than any value of `T`. [endsect] [endsect] diff --git a/doc/12_motivation.qbk b/doc/10_motivation.qbk similarity index 100% rename from doc/12_motivation.qbk rename to doc/10_motivation.qbk diff --git a/doc/13_development.qbk b/doc/11_development.qbk similarity index 100% rename from doc/13_development.qbk rename to doc/11_development.qbk diff --git a/doc/12_when_to_use.qbk b/doc/12_when_to_use.qbk new file mode 100644 index 0000000..80dff54 --- /dev/null +++ b/doc/12_when_to_use.qbk @@ -0,0 +1,37 @@ + +[section When to use Optional] + +It is recommended to use `optional` in situations where there is exactly one, clear (to all parties) reason for having no value of type `T`, and where the lack of value is as natural as having any regular value of `T`. One example of such situation is asking the user in some GUI form to optionally specify some limit on an `int` value, but the user is allowed to say 'I want the number not to be constrained by the maximum'. +For another example, consider a config parameter specifying how many threads the application should launch. Leaving this parameter unspecified means that the application should decide itself. For yet another example, consider a function returning the index of the smallest element in a `vector`. We need to be prepared for the situation, where the `vector` is empty. Therefore a natural signature for such function would be: + + template + optional find_smallest_elem(const std::vector& vec); + +Here, having received an empty `vec` and having no `size_t` to return is not a ['failure] but a ['normal], albeit irregular, situation. + +Another typical situation is to indicate that we do not have a value yet, but we expect to have it later. This notion can be used in implementing solutions like lazy initialization or a two-phase initialization. + +`optional` can be used to take a non-__SGI_DEFAULT_CONSTRUCTIBLE__ type `T` and create a sibling type with a default constructor. This is a way to add a ['null-state] to any type that doesn't have it already. + +Sometimes type `T` already provides a built-in null-state, but it may still be useful to wrap it into `optional`. Consider `std::string`. When you read a piece of text from a GUI form or a DB table, it is hardly ever that the empty string indicates anything else but a missing text. And some data bases do not even distinguish between a null string entry and a non-null string of length 0. Still, it may be practical to use `optional` to indicate in the returned type that we want to treat the empty string in a special dedicated program path: + + if(boost::optional name = ask_user_name()) { + assert(*name != ""); + logon_as(*name); + } + else { + skip_logon(); + } + +In the example above, the assertion indicates that if we choose to use this technique, we must translate the empty string state to an optional object with no contained value (inside function `ask_user_name`). + +[heading Not recommended usages] + +It is not recommended to use `optional` to indicate that we were not able to compute a value because of a ['failure]. It is difficult to define what a failure is, but it usually has one common characteristic: an associated information on the cause of the failure. This can be the type and member data of an exception object, or an error code. It is a bad design to signal a failure and not inform about the cause. If you do not want to use exceptions, and do not like the fact that by returning error codes you cannot return the computed value, you can use [@https://github.com/ptal/Boost.Expected Expected] library. It is sort of __BOOST_VARIANT__ that contains either a computed value or a reason why the computation failed. + +Sometimes the distinction into what is a failure and what is a valid but irregular result is blurry and depends on a particular usage and personal preference. Consider a function that converts a `string` to an `int`. Is it a failure that you cannot convert? It might in some cases, but in other you may call it exactly for the purpose of figuring out if a given `string` is convertible, and you are not even interested in the resulting value. Sometimes when a conversion fails you may not consider it a failure, but you need to know why it cannot be converted; for instance at which character it is determined that the conversion is impossible. In this case returning `optional` will not suffice. Finally, there is a use case where an input string that does not represent an `int` is not a failure condition, but during the conversion we use resources whose acquisition may fail. In that case the natural representation is to both return `optional` and signal failure: + + optional convert1(const string& str); // throws + expected> convert2(const string& str); // return either optional or error + +[endsect] diff --git a/doc/13_relational_operators.qbk b/doc/13_relational_operators.qbk new file mode 100644 index 0000000..2797c27 --- /dev/null +++ b/doc/13_relational_operators.qbk @@ -0,0 +1,35 @@ + +[section Relational operators] + +Type `optional` is __SGI_EQUALITY_COMPARABLE__ whenever `T` is __SGI_EQUALITY_COMPARABLE__. Two optional objects containing a value compare in the same as their contained values. The uninitialized state of `optional` is treated as a distinct value, equal to itself, and unequal to any value of type `T`: + + boost::optional oN = boost::none; + boost::optional o0 = 0; + boost::optional o1 = 1; + + assert(oN != o0); + assert(o1 != oN); + assert(o2 != o1); + assert(oN == oN); + assert(o0 == o0); + +The converting constructor from `T` as well as from `boost::none` implies the existence and semantics of the mixed comparison between `T` and `optional` as well as between `none_t` and `optionl`: + + assert(oN != 0); + assert(o1 != boost::none); + assert(o2 != 1); + assert(oN == boost::none); + assert(o0 == 0); + +This mixed comparison has a practical interpretation, which is occasionally useful: + + boost::optional choice = ask_user(); + if (choice == 2) + start_procedure_2(); + +In the above example, the meaning of the comparison is 'user chose number 2'. If user chose nothing, he didn't choose number 2. + +In a similar manner, type `optional` is __SGI_LESS_THAN_COMPARABLE__ whenever `T` is __SGI_LESS_THAN_COMPARABLE__. The optional object containing no value is compared less than any value of `T`. To illustrate this, if the default ordering of `size_t` is {`0`, `1`, `2`, ...}, the default ordering of `optional` is {`boost::none`, `0`, `1`, `2`, ...}. This order does not have a practical interpretation. The goal is to have any semantically correct default ordering in order for `optional` to be usable in ordered associative containers (wherever `T` is usable). + +Mixed relational operators are the only case where the contained value of an optional object can be inspected without the usage of value accessing function (`operator*`, `value`, `value_or`). +[endsect] diff --git a/doc/html/boost_optional/quick_start/bypassing_unnecessary_default_construction.html b/doc/html/boost_optional/quick_start/bypassing_unnecessary_default_construction.html index 844742b..ed964cf 100644 --- a/doc/html/boost_optional/quick_start/bypassing_unnecessary_default_construction.html +++ b/doc/html/boost_optional/quick_start/bypassing_unnecessary_default_construction.html @@ -44,10 +44,10 @@ boost::tie(begin, end) = getPeriod();

    - The second line works already, this is the capability of Boost.Tuple library, - but the first line won't work. We could set some invented initial dates, - but it is confusing and may be an unacceptable cost, given that these values - will be overwritten in the next line anyway. This is where optional can help: + The second line works already, this is the capability of Boost.Tuple + library, but the first line won't work. We could set some invented initial + dates, but it is confusing and may be an unacceptable cost, given that these + values will be overwritten in the next line anyway. This is where optional can help:

    boost::optional<Date> begin, end;
     boost::tie(begin, end) = getPeriod();
    diff --git a/doc/html/boost_optional/quick_start/storage_in_containers.html b/doc/html/boost_optional/quick_start/storage_in_containers.html
    index 1715431..f13f5a7 100644
    --- a/doc/html/boost_optional/quick_start/storage_in_containers.html
    +++ b/doc/html/boost_optional/quick_start/storage_in_containers.html
    @@ -43,14 +43,9 @@
     

    This works because optional<T> - is LessThanComparable whenever - T is LessThanComparable. - In this case the state of being uninitialized is treated as a yet another - value of T, which is compared - less than any value of T. - So the set of values that type optional<T> - can assume is {boost::none, -2147483648, -2147483647, ..., -1, - 0, 1, ..., 2147483647} (assuming a 32-bit int). + is LessThanComparable whenever T is LessThanComparable. In this case + the state of being uninitialized is treated as a yet another value of T, which is compared less than any value + of T.

    diff --git a/doc/html/boost_optional/tutorial/design_overview/the_interface.html b/doc/html/boost_optional/tutorial/design_overview/the_interface.html index e0c3a31..8fa2707 100644 --- a/doc/html/boost_optional/tutorial/design_overview/the_interface.html +++ b/doc/html/boost_optional/tutorial/design_overview/the_interface.html @@ -7,7 +7,7 @@ - +
    @@ -20,7 +20,7 @@

    -PrevUpHomeNext +PrevUpHomeNext

    @@ -180,7 +180,7 @@
    -PrevUpHomeNext +PrevUpHomeNext
    diff --git a/doc/html/boost_optional/tutorial/optional_references.html b/doc/html/boost_optional/tutorial/optional_references.html index 0ca70b6..4e067c2 100644 --- a/doc/html/boost_optional/tutorial/optional_references.html +++ b/doc/html/boost_optional/tutorial/optional_references.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@
    -PrevUpHomeNext +PrevUpHomeNext

    @@ -109,7 +109,7 @@
    -PrevUpHomeNext +PrevUpHomeNext
    diff --git a/doc/html/boost_optional/tutorial/relational_operators.html b/doc/html/boost_optional/tutorial/relational_operators.html new file mode 100644 index 0000000..be20e45 --- /dev/null +++ b/doc/html/boost_optional/tutorial/relational_operators.html @@ -0,0 +1,108 @@ + + + +Relational operators + + + + + + + + + + + + + + + +
    Boost C++ LibrariesHomeLibrariesPeopleFAQMore
    +
    +
    +PrevUpHomeNext +
    +
    + +

    + Type optional<T> is + EqualityComparable whenever T is EqualityComparable. Two optional + objects containing a value compare in the same as their contained values. + The uninitialized state of optional<T> + is treated as a distinct value, equal to itself, and unequal to any value + of type T: +

    +
    boost::optional<int> oN = boost::none;
    +boost::optional<int> o0 = 0;
    +boost::optional<int> o1 = 1;
    +
    +assert(oN != o0);
    +assert(o1 != oN);
    +assert(o2 != o1);
    +assert(oN == oN);
    +assert(o0 == o0);
    +
    +

    + The converting constructor from T + as well as from boost::none implies the existence and semantics + of the mixed comparison between T + and optional<T> as + well as between none_t and + optionl<T>: +

    +
    assert(oN != 0);
    +assert(o1 != boost::none);
    +assert(o2 != 1);
    +assert(oN == boost::none);
    +assert(o0 == 0);
    +
    +

    + This mixed comparison has a practical interpretation, which is occasionally + useful: +

    +
    boost::optional<int> choice = ask_user();
    +if (choice == 2)
    +    start_procedure_2();
    +
    +

    + In the above example, the meaning of the comparison is 'user chose number + 2'. If user chose nothing, he didn't choose number 2. +

    +

    + In a similar manner, type optional<T> + is LessThanComparable whenever T is LessThanComparable. The optional + object containing no value is compared less than any value of T. To illustrate this, if the default ordering + of size_t is {0, 1, + 2, ...}, the default ordering + of optional<size_t> + is {boost::none, 0, + 1, 2, + ...}. This order does not have a practical interpretation. The goal is to + have any semantically correct default ordering in order for optional<T> to + be usable in ordered associative containers (wherever T + is usable). +

    +

    + Mixed relational operators are the only case where the contained value of + an optional object can be inspected without the usage of value accessing + function (operator*, + value, value_or). +

    +
    + + + +
    +
    +
    +PrevUpHomeNext +
    + + diff --git a/doc/html/boost_optional/tutorial/when_to_use_optional.html b/doc/html/boost_optional/tutorial/when_to_use_optional.html new file mode 100644 index 0000000..5883446 --- /dev/null +++ b/doc/html/boost_optional/tutorial/when_to_use_optional.html @@ -0,0 +1,142 @@ + + + +When to use Optional + + + + + + + + + + + + + + + +
    Boost C++ LibrariesHomeLibrariesPeopleFAQMore
    +
    +
    +PrevUpHomeNext +
    +
    + +

    + It is recommended to use optional<T> + in situations where there is exactly one, clear (to all parties) reason for + having no value of type T, + and where the lack of value is as natural as having any regular value of + T. One example of such situation + is asking the user in some GUI form to optionally specify some limit on an + int value, but the user is allowed + to say 'I want the number not to be constrained by the maximum'. For another + example, consider a config parameter specifying how many threads the application + should launch. Leaving this parameter unspecified means that the application + should decide itself. For yet another example, consider a function returning + the index of the smallest element in a vector. + We need to be prepared for the situation, where the vector + is empty. Therefore a natural signature for such function would be: +

    +
    template <typename T>
    +optional<size_t> find_smallest_elem(const std::vector<T>& vec);
    +
    +

    + Here, having received an empty vec + and having no size_t to return + is not a failure but a normal, + albeit irregular, situation. +

    +

    + Another typical situation is to indicate that we do not have a value yet, + but we expect to have it later. This notion can be used in implementing solutions + like lazy initialization or a two-phase initialization. +

    +

    + optional can be used to take + a non-DefaultConstructible type T and create a sibling type with a default + constructor. This is a way to add a null-state to any + type that doesn't have it already. +

    +

    + Sometimes type T already + provides a built-in null-state, but it may still be useful to wrap it into + optional. Consider std::string. + When you read a piece of text from a GUI form or a DB table, it is hardly + ever that the empty string indicates anything else but a missing text. And + some data bases do not even distinguish between a null string entry and a + non-null string of length 0. Still, it may be practical to use optional<string> + to indicate in the returned type that we want to treat the empty string in + a special dedicated program path: +

    +
    if(boost::optional<std::string> name = ask_user_name()) {
    +    assert(*name != "");
    +    logon_as(*name);
    +}
    +else {
    +    skip_logon();
    +}
    +
    +

    + In the example above, the assertion indicates that if we choose to use this + technique, we must translate the empty string state to an optional object + with no contained value (inside function ask_user_name). +

    +
    + + Not + recommended usages +
    +

    + It is not recommended to use optional + to indicate that we were not able to compute a value because of a failure. + It is difficult to define what a failure is, but it usually has one common + characteristic: an associated information on the cause of the failure. This + can be the type and member data of an exception object, or an error code. + It is a bad design to signal a failure and not inform about the cause. If + you do not want to use exceptions, and do not like the fact that by returning + error codes you cannot return the computed value, you can use Expected + library. It is sort of Boost.Variant + that contains either a computed value or a reason why the computation failed. +

    +

    + Sometimes the distinction into what is a failure and what is a valid but + irregular result is blurry and depends on a particular usage and personal + preference. Consider a function that converts a string + to an int. Is it a failure that + you cannot convert? It might in some cases, but in other you may call it + exactly for the purpose of figuring out if a given string + is convertible, and you are not even interested in the resulting value. Sometimes + when a conversion fails you may not consider it a failure, but you need to + know why it cannot be converted; for instance at which character it is determined + that the conversion is impossible. In this case returning optional<T> + will not suffice. Finally, there is a use case where an input string that + does not represent an int is + not a failure condition, but during the conversion we use resources whose + acquisition may fail. In that case the natural representation is to both + return optional<int> and + signal failure: +

    +
    optional<int> convert1(const string& str); // throws
    +expected<ErrorT, optional<int>> convert2(const string& str); // return either optional or error
    +
    +
    + + + +
    +
    +
    +PrevUpHomeNext +
    + + diff --git a/doc/html/index.html b/doc/html/index.html index 297e7be..51418c3 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -55,6 +55,10 @@
    Motivation
    Design Overview
    +
    When to + use Optional
    +
    Relational + operators
    Optional references
    Rebinding @@ -129,7 +133,7 @@

    - +

    Last revised: June 06, 2014 at 21:50:26 GMT

    Last revised: June 08, 2014 at 14:17:56 GMT


    diff --git a/doc/html/optional/tutorial.html b/doc/html/optional/tutorial.html index f09045f..7b84efd 100644 --- a/doc/html/optional/tutorial.html +++ b/doc/html/optional/tutorial.html @@ -29,6 +29,10 @@
    Motivation
    Design Overview
    +
    When to + use Optional
    +
    Relational + operators
    Optional references
    Rebinding From 07bdbc3743bf87c6381e653bf3ffb050aea6d441 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sun, 8 Jun 2014 20:51:55 +0200 Subject: [PATCH 5/5] docs: optional == nont_t requirements --- doc/13_relational_operators.qbk | 2 ++ doc/html/boost_optional/tutorial/relational_operators.html | 5 +++++ doc/html/index.html | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/13_relational_operators.qbk b/doc/13_relational_operators.qbk index 2797c27..a16d53b 100644 --- a/doc/13_relational_operators.qbk +++ b/doc/13_relational_operators.qbk @@ -29,6 +29,8 @@ This mixed comparison has a practical interpretation, which is occasionally usef In the above example, the meaning of the comparison is 'user chose number 2'. If user chose nothing, he didn't choose number 2. +In case where `optional` is compared to `none`, it is not required that `T` be __SGI_EQUALITY_COMPARABLE__. + In a similar manner, type `optional` is __SGI_LESS_THAN_COMPARABLE__ whenever `T` is __SGI_LESS_THAN_COMPARABLE__. The optional object containing no value is compared less than any value of `T`. To illustrate this, if the default ordering of `size_t` is {`0`, `1`, `2`, ...}, the default ordering of `optional` is {`boost::none`, `0`, `1`, `2`, ...}. This order does not have a practical interpretation. The goal is to have any semantically correct default ordering in order for `optional` to be usable in ordered associative containers (wherever `T` is usable). Mixed relational operators are the only case where the contained value of an optional object can be inspected without the usage of value accessing function (`operator*`, `value`, `value_or`). diff --git a/doc/html/boost_optional/tutorial/relational_operators.html b/doc/html/boost_optional/tutorial/relational_operators.html index be20e45..ecb8c4f 100644 --- a/doc/html/boost_optional/tutorial/relational_operators.html +++ b/doc/html/boost_optional/tutorial/relational_operators.html @@ -71,6 +71,11 @@ In the above example, the meaning of the comparison is 'user chose number 2'. If user chose nothing, he didn't choose number 2.

    +

    + In case where optional<T> is + compared to none, it is not + required that T be EqualityComparable. +

    In a similar manner, type optional<T> is LessThanComparable whenever T is LessThanComparable. The optional diff --git a/doc/html/index.html b/doc/html/index.html index 51418c3..af4424e 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -133,7 +133,7 @@

    - +

    Last revised: June 08, 2014 at 14:17:56 GMT

    Last revised: June 08, 2014 at 18:14:37 GMT