diff --git a/doc/optional.html b/doc/optional.html index 895312d..61a29c5 100644 --- a/doc/optional.html +++ b/doc/optional.html @@ -3,7 +3,6 @@ - @@ -324,6 +323,8 @@ class optional optional ( T const& v ) ; + optional ( bool condition, T const& v ) ; [new in 1.34] + optional ( optional const& rhs ) ; template<class U> explicit optional ( optional<U> const& rhs ) ; @@ -347,6 +348,8 @@ class optional T const& get() const ; T& get() ; + T const& get_value_or( T const& default ) const ; [new in 1.34] + T const* operator ->() const ; T* operator ->() ; @@ -380,6 +383,12 @@ template<class T> inline bool operator <= ( optional<T> const& x, op template<class T> inline bool operator >= ( optional<T> const& x, optional<T> const& y ) ; +template<class T> inline optional<T> make_optional ( T const& v ) ; [new in 1.34] + +template<class T> inline optional<T> make_optional ( bool condition, T const& v ) ; [new in 1.34] + +template<class T> inline T const& get_optional_value_or ( optional<T> const& opt, T const& default ) ; [new in 1.34] + template<class T> inline T const& get ( optional<T> const& opt ) ; template<class T> inline T& get ( optional<T> & opt ) ; @@ -436,7 +445,7 @@ assert ( !def ) ;
optional<T>::optional( none_t );
-

Effect: Constructs an optional uninitialized.

+

Effect: Constructs an optional uninitialized.

Postconditions: *this is uninitialized.

Throws: Nothing.

Notes:

@@ -459,7 +468,6 @@ assert ( !n ) ;
optional<T (not a ref)>::optional( T const& v )

Effect: Directly-Constructs an optional.

-

Postconditions: *this is initialized and its value is a copy of 'v'.

Throws: Whatever T::T( T const& ) throws.

Notes: T::T( T const& ) is called.

@@ -495,6 +503,23 @@ assert (*opt == v);
+
optional<T (not a ref)>::optional( bool condition, T const& v ) ;
+optional<T&>           ::optional( bool condition, T&       v ) ;
+
+ +
+

If condition is true, same as:

+
optional<T (not a ref)>::optional( T const& v )
+optional<T&>           ::optional( T&       v )
+
+

otherwise, same as:

+
optional<T (not a ref)>::optional()
+optional<T&>           ::optional()
+
+
+ +
+
optional<T (not a ref)>::optional( optional const& rhs );

Effect: Copy-Constructs an optional.

@@ -797,7 +822,6 @@ assert ( *opt1 == static_cast<U>(v) ) ;
-
T const& optional<T (not a ref)>::operator*() const ;
 T&       optional<T (not a ref)>::operator*();
@@ -828,6 +852,32 @@ assert ( *opt == w ) ;
+
T const& optional<T (not a ref)>::get_value_or( T const& default) const ;
+T&       optional<T (not a ref)>::get_value_or( T&       default ) ;
+
+inline T const& get_optional_value_or ( optional<T (not a ref)> const& o, T const& default ) ;
+inline T&       get_optional_value_or ( optional<T (not a ref)>&       o, T&       default ) ;
+
+
+

Returns: A reference to the contained value, if any, or default

+

Throws: Nothing.

+

Example:

+
+
T v, z ;
+optional<T> def;
+T const& y = def.get_value_or(z);
+assert ( y == z ) ;
+
+optional<T> opt ( v );
+T const& u = get_optional_value_or(opt,z);
+assert ( u == v ) ;
+assert ( u != z ) ;
+
+
+

+
+
+
T const& optional<T&>::operator*() const ;
 T      & optional<T&>::operator*();
@@ -965,18 +1015,47 @@ assert ( opt.is_initialized() );
+
optional<T (not a ref)> make_optional( T const& v )
+
+

Returns: optional<T>(v) for the deduced type T of v.

+

Example:

+
+
template<class T> void foo ( optional<T> const& opt ) ;
+
+foo ( make_optional(1+1) ) ; // Creates an optional<int>
+
+
+
+ +
optional<T (not a ref)> make_optional( bool condition, T const& v )
+
+

Returns: optional<T>(condition,v) for the deduced type T of v.

+

Example:

+
+
optional<double> calculate_foo()
+{
+  double val = compute_foo();
+  return make_optional(is_not_nan_and_finite(val),val);
+}
+
+optional<double> v = calculate_foo();
+if ( !v )
+  error("foo wasn't computed");
+
+
+ +
+
bool operator == ( optional<T> const& x, optional<T> const& y );

Returns: If both x and y are initialied, (*x == *y). -If only x or y is initialized, false. If both are uninitialized, true. -

+If only x or y is initialized, false. If both are uninitialized, true.

Throws: Nothing.

Notes: Pointers have shallow relational operators while optional has deep relational operators. Do not use operator == directly in generic code which expect to be given either an optional<T> or a pointer; -use equal_pointees() instead -

+use equal_pointees() instead

Example:

T x(12);
@@ -1012,14 +1091,12 @@ assert ( optX != optZ ) ;
 

Returns: If y is not initialized, false. If y is initialized and x is not initialized, true. -If both x and y are initialized, (*x < *y). -

+If both x and y are initialized, (*x < *y).

Throws: Nothing.

Notes: Pointers have shallow relational operators while optional has deep relational operators. Do not use operator < directly in generic code which expect to be given either an optional<T> or a pointer; -use less_pointees() instead -

+use less_pointees() instead

Example:

T x(12);
@@ -1082,23 +1159,17 @@ assert ( optX != optZ ) ;
 
void swap ( optional<T>& x, optional<T>& y );
-

Effect: If both x and y are initialized, calls swap(*x,*y) -using std::swap.
+

Effect: If both x and y are initialized, calls swap(*x,*y) using std::swap.
If only one is initialized, say x, calls: y.reset(*x); x.reset();
-If none is initialized, does nothing. -

+If none is initialized, does nothing.

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 const& ) throws. -

-

Notes: If both are initialized, swap(T&,T&) is used unqualified -but with std::swap introduced in scope.
-If only one is initialized, T::~T() and T::T( T const& ) is called. -

+If only one is initialized, whatever T::T ( T const& ) throws.

+

Notes: If both are initialized, swap(T&,T&) is used unqualified but with std::swap introduced in scope.
+If only one is initialized, T::~T() and T::T( T const& ) is called.

Exception Safety: If both are initialized, this operation has the exception safety guarantees of swap(T&,T&).
-If only one is initialized, it has the same basic guarantee as optional<T>::reset( T const& ). -

+If only one is initialized, it has the same basic guarantee as optional<T>::reset( T const& ).

Example:

T x(12);
@@ -1254,8 +1325,7 @@ assert(a==b);
 b = 3 ;
 assert(ra!=b); // 'ra' is not rebound to 'b'
 
-

Now, if you assign to an initialized optional<T&>, the effect is to -rebind to the new object instead of assigning the referee. This is unlike +

Now, if you assign to an initialized optional<T&>, the effect is to rebind to the new object instead of assigning the referee. This is unlike bare C++ references.

int a = 1 ;
 int b = 2 ;
@@ -1358,8 +1428,7 @@ public:
 

A limitation of this method is that it doesn't scale well to wrapped objects with multiple constructors nor to generic code were the constructor overloads are unknown.

-

The solution presented in this library is the family of InPlaceFactories and -TypedInPlaceFactories.
+

The solution presented in this library is the family of InPlaceFactories and TypedInPlaceFactories.
These factories are a family of classes which encapsulate an increasing number of arbitrary constructor parameters and supply a method to construct an object of a given type using those parameters at an address specified by the user via placement new.

@@ -1427,10 +1496,7 @@ public: W ( in_place(123,"hello") ) ; }
-

The factories are implemented in the headers: -in_place_factory.hpp and -typed_in_place_factory.hpp -

+

The factories are implemented in the headers: in_place_factory.hpp and typed_in_place_factory.hpp


@@ -1473,8 +1539,7 @@ of the assignment methods:

TypedInPlaceFactory const& )
  • optional<T>:::reset ( T const&)
  • -

    Can only guarantee the basic exception safety: The lvalue optional is left uninitialized -if an exception is thrown (any previous value is first destroyed using T::~T())

    +

    Can only guarantee the basic exception safety: The lvalue optional is left uninitialized if an exception is thrown (any previous value is first destroyed using T::~T())

    On the other hand, the uninitializing methods:

    \ No newline at end of file diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 4421f4a..8a78a40 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -185,6 +185,16 @@ class optional_base : public optional_tag { construct(val); } + + // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional. + // Can throw if T::T(T const&) does + optional_base ( bool cond, argument_type val ) + : + m_initialized(false) + { + if ( cond ) + construct(val); + } // Creates a deep copy of another optional // Can throw if T::T(T const&) does @@ -455,6 +465,9 @@ class optional : public optional_detail::optional_base // Can throw if T::T(T const&) does optional ( argument_type val ) : base(val) {} + // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. + // Can throw if T::T(T const&) does + optional ( bool cond, argument_type val ) : base(cond,val) {} #ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR // NOTE: MSVC needs templated versions first @@ -549,6 +562,10 @@ class optional : public optional_detail::optional_base reference_const_type get() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); } reference_type get() { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); } + // Returns a copy of the value if this is initialized, 'v' otherwise + reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; } + reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; } + // Returns a pointer to the value if this is initialized, otherwise, // the behaviour is UNDEFINED // No-throw @@ -570,6 +587,22 @@ class optional : public optional_detail::optional_base bool operator!() const { return !this->is_initialized() ; } } ; +// Returns optional(v) +template +inline +optional make_optional ( T const& v ) +{ + return optional(v); +} + +// Returns optional(cond,v) +template +inline +optional make_optional ( bool cond, T const& v ) +{ + return optional(cond,v); +} + // Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED. // No-throw template @@ -606,6 +639,24 @@ get ( optional* opt ) return opt->get_ptr() ; } +// Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED. +// No-throw +template +inline +BOOST_DEDUCED_TYPENAME optional::reference_const_type +get_optional_value_or ( optional const& opt, BOOST_DEDUCED_TYPENAME optional::reference_const_type v ) +{ + return opt.get_value_or(v) ; +} + +template +inline +BOOST_DEDUCED_TYPENAME optional::reference_type +get_optional_value_or ( optional& opt, BOOST_DEDUCED_TYPENAME optional::reference_type v ) +{ + return opt.get_value_or(v) ; +} + // Returns a pointer to the value if this is initialized, otherwise, returns NULL. // No-throw template @@ -767,10 +818,6 @@ template inline void swap ( optional& x, optional& y ) optional_detail::optional_swap(x,y); } -template inline optional make_optional ( T const& v ) -{ - return optional(v); -} } // namespace boost diff --git a/test/optional_test.cpp b/test/optional_test.cpp index 12dda2a..5c10eed 100644 --- a/test/optional_test.cpp +++ b/test/optional_test.cpp @@ -15,7 +15,9 @@ #define BOOST_ENABLE_ASSERT_HANDLER -#include "boost/optional.hpp" +#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin + +#include "boost/optional/optional.hpp" #ifdef __BORLANDC__ #pragma hdrstop @@ -151,6 +153,95 @@ void test_basics( T const* ) ob.reset(); check_is_pending_dtor( ARG(T) ) ; check_uninitialized(ob); + +} + +template +void test_conditional_ctor_and_get_valur_or ( T const* ) +{ + TRACE( std::endl << BOOST_CURRENT_FUNCTION ); + + T a(321); + + T z(123); + + optional const cdef0(false,a); + + optional def0(false,a); + optional def1 = boost::make_optional(false,a); // T is not within boost so ADL won't find make_optional unqualified + check_uninitialized(def0); + check_uninitialized(def1); + + optional const co0(true,a); + + optional o0(true,a); + optional o1 = boost::make_optional(true,a); // T is not within boost so ADL won't find make_optional unqualified + + check_initialized(o0); + check_initialized(o1); + check_value(o0,a,z); + check_value(o1,a,z); + + T b = def0.get_value_or(z); + BOOST_CHECK( b == z ) ; + + b = get_optional_value_or(def0,z); + BOOST_CHECK( b == z ) ; + + b = o0.get_value_or(z); + BOOST_CHECK( b == a ) ; + + b = get_optional_value_or(o0,z); + BOOST_CHECK( b == a ) ; + + + T const& crz = z ; + T& rz = z ; + + T const& crzz = def0.get_value_or(crz); + BOOST_CHECK( crzz == crz ) ; + + T& rzz = def0.get_value_or(rz); + BOOST_CHECK( rzz == rz ) ; + + T const& crzzz = get_optional_value_or(cdef0,crz); + BOOST_CHECK( crzzz == crz ) ; + + T& rzzz = get_optional_value_or(def0,rz); + BOOST_CHECK( rzzz == rz ) ; + + T const& crb = o0.get_value_or(crz); + BOOST_CHECK( crb == a ) ; + + T& rb = o0.get_value_or(rz); + BOOST_CHECK( rb == b ) ; + + T const& crbb = get_optional_value_or(co0,crz); + BOOST_CHECK( crbb == b ) ; + + T const& crbbb = get_optional_value_or(o0,crz); + BOOST_CHECK( crbbb == b ) ; + + T& rbb = get_optional_value_or(o0,rz); + BOOST_CHECK( rbb == b ) ; + + T& ra = a ; + + optional defref(false,ra); + BOOST_CHECK(!defref); + + optional ref(true,ra); + BOOST_CHECK(!!ref); + + a = T(432); + + BOOST_CHECK( *ref == a ) ; + + T& r1 = defref.get_value_or(z); + BOOST_CHECK( r1 == z ) ; + + T& r2 = ref.get_value_or(z); + BOOST_CHECK( r2 == a ) ; } // @@ -688,6 +779,7 @@ void test_with_builtin_types() TRACE( std::endl << BOOST_CURRENT_FUNCTION ); test_basics( ARG(double) ); + test_conditional_ctor_and_get_valur_or( ARG(double) ); test_uninitialized_access( ARG(double) ); test_no_throwing_swap( ARG(double) ); test_relops( ARG(double) ) ; @@ -699,6 +791,7 @@ void test_with_class_type() TRACE( std::endl << BOOST_CURRENT_FUNCTION ); test_basics( ARG(X) ); + test_conditional_ctor_and_get_valur_or( ARG(X) ); test_direct_value_manip( ARG(X) ); test_uninitialized_access( ARG(X) ); test_throwing_direct_init( ARG(X) );