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; +} + +