forked from boostorg/optional
Compare commits
9 Commits
svn-branch
...
svn-branch
Author | SHA1 | Date | |
---|---|---|---|
172b90d2b8 | |||
e1ffaf38b6 | |||
a6f4615d5f | |||
b831e5f88d | |||
88d002a7be | |||
dda39772ad | |||
ed504fae7b | |||
9a0013d668 | |||
361d945b5c |
@ -3,7 +3,10 @@
|
||||
<HTML>
|
||||
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../boost.css">
|
||||
<TITLE>Header </TITLE>
|
||||
</HEAD>
|
||||
@ -20,6 +23,7 @@ HREF="../../../boost/optional/optional.hpp">boost/optional/optional.hpp</A>>
|
||||
<DT><A HREF="#semantics">Semantics</A></DT>
|
||||
<DT><A HREF="#examples">Examples</A></DT>
|
||||
<DT><A HREF="#ref">Optional references</A></DT>
|
||||
<DT><A HREF="#refassign">Rebinding semantics for assignment of optional references</A></DT>
|
||||
<DT><A HREF="#inplace">In-Place Factories</A></DT>
|
||||
<DT><A HREF="#bool">A note about optional<bool></A></DT>
|
||||
<DT><A HREF="#exsafety">Exception Safety Guarantees</A></DT>
|
||||
@ -41,7 +45,7 @@ HREF="../../../boost/optional/optional.hpp">boost/optional/optional.hpp</A>>
|
||||
<P>There are different approaches to the issue of not having a value to return.</P>
|
||||
<P>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 asssert in a debug build)
|
||||
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
|
||||
@ -99,13 +103,15 @@ if ( p.second )
|
||||
If the declaration uses an empty initializer (no initial value is given),
|
||||
and neither default nor value initialization applies, it is said that the object is
|
||||
<i><b>uninitialized</b></i>. Its actual value exist but has an
|
||||
<i>indeterminate inital value</i> (c.f. 8.5.9).<br>
|
||||
<code>optional<T></code> intends to formalize the notion of initialization/no-initialization
|
||||
<i>indeterminate initial value</i> (c.f. 8.5.9).<br>
|
||||
<code>optional<T></code> intends to formalize the notion of initialization
|
||||
(or lack of it)
|
||||
allowing a program to test whether an object has been initialized and stating that access to
|
||||
the value of an uninitialized object is undefined behaviour. That is,
|
||||
the value of an uninitialized object is undefined behavior. That is,
|
||||
when a variable is declared as optional<T> and no initial value is given,
|
||||
the variable is formally uninitialized. A formally uninitialized optional object has conceptually
|
||||
no value at all and this situation can be tested at runtime. It is formally <i>undefined behaviour</i>
|
||||
the variable is <i>formally</i> uninitialized. A formally uninitialized optional object has conceptually
|
||||
no value at all and this situation can be tested at runtime. It is formally <i>
|
||||
undefined behavior</i>
|
||||
to try to access the value of an uninitialized optional. An uninitialized optional can be <i>assigned</i> a value, in which case its initialization state changes to initialized. Furthermore, given the formal
|
||||
treatment of initialization states in optional objects, it is even possible to reset an optional to <i>uninitialized</i>.</P>
|
||||
<P>In C++ there is no formal notion of uninitialized objects, which
|
||||
@ -122,17 +128,18 @@ if ( p.second )
|
||||
Using the <a href="../../../doc/html/variant.html">Boost.Variant</a> library, this model can be implemented
|
||||
in terms of <code>boost::variant<T,nil_t></code>.<br>
|
||||
There is precedence for a discriminated union as a model for an optional value: the
|
||||
<a href="http://www.haskell.org/"><u>Haskell</u></a> <b>Maybe</b> builtin type constructor,
|
||||
thus a discriminated union <code>T+nil_t</code> serves as a conceptual foundation.</p>
|
||||
<a href="http://www.haskell.org/"><u>Haskell</u></a> <b>Maybe</b> built-in type constructor.
|
||||
Thus, a discriminated union <code>T+nil_t</code> serves as a conceptual foundation.</p>
|
||||
<p>A <code>variant<T,nil_t></code> follows naturally from the traditional idiom of extending
|
||||
the range of possible values adding an additional sentinel value with the special meaning of <i>Nothing. </i>
|
||||
However, this additional <i>Nothing</i> value is largely irrelevant for our purpose
|
||||
since our goal is to formalize the notion of uninitialized objects and, while a special extended value <i>can</i> be used to convey that meaning, it is not strictly neccesary in order to do so.</p>
|
||||
since our goal is to formalize the notion of uninitialized objects and, while a special extended value <i>can</i> be used to convey that meaning, it is not strictly
|
||||
necessary in order to do so.</p>
|
||||
<p>The observation made in the last paragraph about the irrelevant nature of the additional <code>nil_t</code> with respect to
|
||||
<u>purpose</u> of optional<T> suggests
|
||||
an alternative model: a <i>container</i> that either has a value of T or nothing.
|
||||
</p>
|
||||
<p>As of this writting I don't know of any precedence for a variable-size fixed-capacity (of 1)
|
||||
<p>As of this writing I don't know of any precedence for a variable-size fixed-capacity (of 1)
|
||||
stack-based container model for optional values, yet I believe this is the consequence of
|
||||
the lack of practical implementations of such a container rather than an inherent shortcoming
|
||||
of the container model.</p>
|
||||
@ -146,7 +153,8 @@ For instance, these models show the <i>exact</i> semantics required for a wrappe
|
||||
<li>If the variant's current type is T, it is modeling an <i>initialized</i> optional.</li>
|
||||
<li>If the variant's current type is not T, it is modeling an <i>uninitialized</i> optional.</li>
|
||||
<li>Testing if the variant's current type is T models testing if the optional is initialized</li>
|
||||
<li>Trying to extract a T from a variant when its current type is not T, models the undefined behaviour
|
||||
<li>Trying to extract a T from a variant when its current type is not T, models the undefined
|
||||
behavior
|
||||
of trying to access the value of an uninitialized optional</li>
|
||||
</blockquote>
|
||||
<p>Single-element container:</p>
|
||||
@ -156,7 +164,7 @@ of trying to access the value of an uninitialized optional</li>
|
||||
<li>If the container is not empty (contains an object of type T), it is modeling an <i>initialized</i> optional.</li>
|
||||
<li>If the container is empty, it is modeling an <i>uninitialized</i> optional.</li>
|
||||
<li>Testing if the container is empty models testing if the optional is initialized</li>
|
||||
<li>Trying to extract a T from an empty container models the undefined behaviour
|
||||
<li>Trying to extract a T from an empty container models the undefined behavior
|
||||
of trying to access the value of an uninitialized optional</li>
|
||||
</blockquote>
|
||||
|
||||
@ -169,7 +177,8 @@ plus the additional semantics corresponding to this special state.<br>
|
||||
As such, <code>optional<T></code> could be thought of as a <i>supertype</i> of T. Of course,
|
||||
we can't do that in C++, so we need to compose the desired semantics using a different mechanism.<br>
|
||||
Doing it the other way around, that is, making <code>optional<T></code> a <i>subtype</i> of T is not only
|
||||
conceptually wrong but also impractical: it is not allowed to derive from a non-class type, such as a builtin type.</p>
|
||||
conceptually wrong but also impractical: it is not allowed to derive from a non-class type, such as a
|
||||
built-in type.</p>
|
||||
|
||||
<p>We can draw from the purpose of optional<T> the required basic semantics:</p>
|
||||
|
||||
@ -180,34 +189,32 @@ object.</p>
|
||||
<p><b>Direct Value Construction via copy:</b> To introduce a formally
|
||||
initialized wrapped object whose value is obtained as a copy of some object.</p>
|
||||
|
||||
<p><b>Deep Copy Construction:</b> To obtain a different yet equivalent wrapped
|
||||
<p><b>Deep Copy Construction:</b> To obtain a new yet equivalent wrapped
|
||||
object.</p>
|
||||
|
||||
<p><b>Direct Value Assignment (upon initialized):</b> To assign the wrapped object a value obtained
|
||||
as a copy of some object.</p>
|
||||
<p><b>Direct Value Assignment (upon initialized):</b> To assign a value to the wrapped object.</p>
|
||||
|
||||
<p><b>Direct Value Assignment (upon uninitialized):</b> To initialize the wrapped object
|
||||
with a value obtained
|
||||
as a copy of some object.</p>
|
||||
|
||||
<p><b>Assignnment (upon initialized):</b> To assign the wrapped object a value obtained as a copy
|
||||
of another wrapper's object.</p>
|
||||
<p><b>Assignment (upon initialized):</b> To assign to the wrapped object the value
|
||||
of another wrapped object.</p>
|
||||
|
||||
<p><b>Assignnment (upon uninitialized):</b> To initialize the wrapped object
|
||||
with value obtained as a copy
|
||||
of another wrapper's object.</p>
|
||||
<p><b>Assignment (upon uninitialized):</b> To initialize the wrapped object
|
||||
with value of another wrapped object.</p>
|
||||
|
||||
<p><b>Deep Relational Operations (when supported by the type T):</b> To compare
|
||||
wrapped object values taking into account the presence of uninitialized
|
||||
operands.</p>
|
||||
states.</p>
|
||||
|
||||
<p><b>Value access:</b> To unwrap the wrapped object.</p>
|
||||
|
||||
<p><b>Initialization state query:</b> To determine if the object is formally
|
||||
initialized or not.</p>
|
||||
|
||||
<p><b>Swap:</b> To exchange wrapper's objects. (with whatever exception safety
|
||||
guarantiees are provided by T's swap).</p>
|
||||
<p><b>Swap:</b> To exchange wrapped objects. (with whatever exception safety
|
||||
guarantees are provided by T's swap).</p>
|
||||
|
||||
<p><b>De-initialization:</b> To release the wrapped object (if any) and leave
|
||||
the wrapper in the uninitialized state.</p>
|
||||
@ -234,7 +241,7 @@ those operations which are well defined (w.r.t the type T) even if any of the
|
||||
operands are uninitialized. These operations include: construction,
|
||||
copy-construction, assignment, swap and relational operations.<br>
|
||||
For the value access operations, which are undefined (w.r.t the type T) when the
|
||||
operand is uninitialized, a different interface is choosen (which will be
|
||||
operand is uninitialized, a different interface is chosen (which will be
|
||||
explained next).<br>
|
||||
Also, the presence of the possibly uninitialized state requires additional
|
||||
operations not provided by T itself which are supported by a special interface.</p>
|
||||
@ -259,7 +266,7 @@ optional objects: The operators * and -></h3>
|
||||
the implied pointee actually exist.</P>
|
||||
<P>Such a <i>de facto</i> idiom for referring to optional objects can be formalized in the form of a
|
||||
concept: the <a href="../../utility/OptionalPointee.html">OptionalPointee</a> concept.<br>
|
||||
This concept captures the syntactic usage of operatos *, -> and conversion to bool to convey
|
||||
This concept captures the syntactic usage of operators *, -> and conversion to bool to convey
|
||||
the notion of optionality.</P>
|
||||
<P>However, pointers are good to <u>refer</u> to optional objects, but not particularly good
|
||||
to handle the optional objects in all other respects, such as initializing or moving/copying
|
||||
@ -273,22 +280,22 @@ them. The problem resides in the shallow-copy of pointer semantics: if you need
|
||||
allocation and use a smart pointer to automatically handle the details of this.
|
||||
For example, if a function is to optionally return an object X, it can use shared_ptr<X>
|
||||
as the return value. However, this requires dynamic allocation of X. If X is
|
||||
a builtin or small POD, this technique is very poor in terms of required resources.
|
||||
a built-in or small POD, this technique is very poor in terms of required resources.
|
||||
Optional objects are essentially values so it is very convenient to be able to use automatic
|
||||
storage and deep-copy semantics to manipulate optional values just as we do with ordinary
|
||||
values. Pointers do not have this semantics, so are unappropriate for the initialization and
|
||||
values. Pointers do not have this semantics, so are inappropriate for the initialization and
|
||||
transport of optional values, yet are quite convenient for handling the access to the
|
||||
possible undefined value because of the idiomatic aid present in the OptionalPointee
|
||||
concept incarnated by pointers.
|
||||
</p>
|
||||
<h4>Optional<T> as a model of OptionalPointee</h4>
|
||||
<P>For value access operations optional<> uses operators * and -> to lexically
|
||||
warn about the possibliy uninitialized state appealing to the familiar pointer
|
||||
warn about the possibly uninitialized state appealing to the familiar pointer
|
||||
semantics w.r.t. to null pointers.<br>
|
||||
<u><b>However, it is particularly important to note that optional<> objects are not pointers. optional<>
|
||||
is not, and does not model, a pointer</b></u><b>.</b>
|
||||
<P>For instance, optional<> has not shallow-copy so does not alias: two different optionals
|
||||
never refer to the <i>same</i> value unless T itself is an reference (but my have <i>equivalent</i> values).<br>
|
||||
<P>For instance, optional<> does not have shallow-copy so does not alias: two different optionals
|
||||
never refer to the <i>same</i> value unless T itself is a reference (but may have <i>equivalent</i> values).<br>
|
||||
The difference between an optional<T> and a pointer must be kept in mind, particularly
|
||||
because the semantics of relational operators are different: since optional<T>
|
||||
is a value-wrapper, relational operators are deep: they compare optional values;
|
||||
@ -313,7 +320,7 @@ class optional
|
||||
|
||||
optional () ;
|
||||
|
||||
optional ( detail::none_t ) ;
|
||||
optional ( none_t ) ;
|
||||
|
||||
optional ( T const& v ) ;
|
||||
|
||||
@ -325,7 +332,7 @@ class optional
|
||||
|
||||
template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ;
|
||||
|
||||
optional& operator = ( detail::none_t ) ;
|
||||
optional& operator = ( none_t ) ;
|
||||
|
||||
optional& operator = ( T const& v ) ;
|
||||
|
||||
@ -427,7 +434,7 @@ assert ( !def ) ;</pre>
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>optional<T>::optional( detail::none_t );</pre>
|
||||
<pre>optional<T>::optional( none_t );</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> Constructs an <b>optional </b>uninitialized.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is <u>uninitialized</u>.</p>
|
||||
@ -436,11 +443,12 @@ assert ( !def ) ;</pre>
|
||||
<blockquote>
|
||||
<p>T's default constructor <u><i>is not</i></u> called.<br>
|
||||
The
|
||||
expression <code>boost::none</code> denotes an instance of <code>boost::detail::none_t</code> that can be
|
||||
expression <code>boost::none</code> denotes an instance of <code>boost::none_t</code> that can be
|
||||
used as the parameter.</p>
|
||||
</blockquote>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>#include <boost/none.hpp></pre>
|
||||
<pre>optional<T> n(none) ;
|
||||
assert ( !n ) ;</pre>
|
||||
</blockquote>
|
||||
@ -468,7 +476,7 @@ assert ( *opt == v ) ;</pre>
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>optional<T&>::optional( T ref )</pre>
|
||||
<pre>optional<T&>::optional( T& ref )</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> Directly-Constructs an <b>optional</b>.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is <u>initialized</u> and its value is an
|
||||
@ -522,12 +530,11 @@ assert ( init2 == init ) ;
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> Copy-Constructs an <b>optional</b>.</p>
|
||||
<p><b>Postconditions:</b> If <b>rhs</b> is initialized, <b>*this</b> is initialized
|
||||
and its value is a <i>copy</i> of the internal wrapper holding the references in <b>rhs</b>; else <b>*this</b>
|
||||
and its value is another reference to the same object referenced by <b>*rhs</b>; else <b>*this</b>
|
||||
is uninitialized.</p>
|
||||
<p><b>Throws:</b> Nothing.</p>
|
||||
<p><b>Notes:</b> If <b>rhs</b> is initialized, the internal wrapper will be
|
||||
copied and just like true references, both <b>*this</b> and <b>rhs</b> will
|
||||
referr to the same object<b> </b>(will alias).</p>
|
||||
<p><b>Notes:</b> If <b>rhs</b> is initialized, both <b>*this</b> and <b>*rhs</b> will
|
||||
reefer to the same object<b> </b>(they alias).</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>optional<T&> uninit ;
|
||||
@ -542,6 +549,13 @@ assert ( *init == v ) ;
|
||||
|
||||
optional<T> init2 ( init ) ;
|
||||
assert ( *init2 == v ) ;
|
||||
|
||||
v = 3 ;
|
||||
|
||||
assert ( *init == 3 ) ;
|
||||
assert ( *init2 == 3 ) ;
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
</blockquote>
|
||||
@ -584,7 +598,7 @@ assert( *y == 123 ) ;
|
||||
<p><b>Effect:</b> Constructs an <b>optional</b> with a value of T obtained from
|
||||
the factory.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is <u>initialized</u> and its value is
|
||||
<i>directly given</i> from the factory 'f' (i.e, the value<u> is not copied</u>).</p>
|
||||
<i>directly given</i> from the factory 'f' (i.e., the value<u> is not copied</u>).</p>
|
||||
<p><b>Throws:</b> Whatever the T constructor called by the factory throws.</p>
|
||||
<p><b>Notes:</b> See <A HREF="#inplace">In-Place Factories</A></p>
|
||||
<p><b>Exception Safety:</b> Exceptions can only be thrown during the call to the
|
||||
@ -615,22 +629,55 @@ assert ( *y == v ) ;
|
||||
<p><b>Effect:</b> Assigns the value 'rhs' to an <b>optional</b>.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is initialized
|
||||
and its value is a <i>copy</i> of <b>rhs.</b></p>
|
||||
<p><b>Throws:</b> Whatever T::T( T const& ) throws.</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, it is first reset to uninitialized
|
||||
using T::~T(), then T::T(<b>rhs</b>) is called.</p>
|
||||
<p><b>Exception Safety:</b> <u>Basic:</u> Exceptions can only be thrown during T::T( T const& );
|
||||
in that case, <b>*this</b> is left <u>uninitialized</u>.
|
||||
</p>
|
||||
<p><b>Throws:</b> Whatever T::operator=( T const& ) or T::T(T const&) throws.</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, T's assignment operator is
|
||||
used, otherwise, its copy-constructor is used.</p>
|
||||
<p><b>Exception Safety:</b> In the event of an exception, the initialization
|
||||
state of <b>*this</b> is unchanged and its value unspecified as far as optional
|
||||
is concerned (it is up to T's operator=()) [If <b>*this</b> is initially
|
||||
uninitialized and T's <i>copy constructor</i> fails, <b>*this</b> is left
|
||||
properly uninitialized]</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>T x;
|
||||
optional<T> def ;
|
||||
optional<T> opt(x) ;
|
||||
|
||||
T y;
|
||||
def = y ;
|
||||
assert ( *def == y ) ;
|
||||
opt = y ;
|
||||
assert ( *opt == y ) ;
|
||||
// previous value (copy of 'v') destroyed from within 'opt'.
|
||||
assert ( *opt == y ) ;</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>optional<T&>& optional<T&>::operator= ( T& const& rhs ) ;</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> (Re)binds thee wrapped reference.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is initialized
|
||||
and it references the same object referenced by <b>rhs.</b></p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, is is <i>rebound</i> to the
|
||||
new object. See <A HREF="#refassign">here</a> for details on this behavior.</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>int a = 1 ;
|
||||
int b = 2 ;
|
||||
T& ra = a ;
|
||||
T& rb = b ;
|
||||
optional<int&> def ;
|
||||
optional<int&> opt(ra) ;
|
||||
|
||||
def = rb ; // binds 'def' to 'b' through 'rb'
|
||||
assert ( *def == b ) ;
|
||||
*def = a ; // changes the value of 'b' to a copy of the value of 'a'
|
||||
assert ( b == a ) ;
|
||||
int c = 3;
|
||||
int& rc = c ;
|
||||
opt = rc ; // REBINDS to 'c' through 'rc'
|
||||
c = 4 ;
|
||||
assert ( *opt == 4 ) ;
|
||||
</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
@ -644,21 +691,25 @@ assert ( *opt == y ) ;
|
||||
and its value is a <i>copy</i> of the value of <b>rhs</b>; else <b>*this</b>
|
||||
is uninitialized.
|
||||
</p>
|
||||
<p><b>Throws:</b> Whatever T::T( T const& ) throws.</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, it is first reset to uninitialized
|
||||
using T::~T(), then T::T( T const& ) is called if <b>rhs</b> is initialized.
|
||||
</p>
|
||||
<p><b>Exception Safety:</b> <u>Basic:</u> Exceptions can only be thrown during T::T( T const& );
|
||||
in that case, <b>*this</b> is left <u>uninitialized</u>.
|
||||
<p><b>Throws:</b> Whatever T::operator( T const&) or T::T( T const& ) throws.</p>
|
||||
<p><b>Notes:</b> If both<b> *this</b> and <b>rhs</b> are initially initialized,
|
||||
T's <i>assignment</i> <i>operator</i> is used. If <b>*this</b> is initially initialized but <b>
|
||||
rhs</b> is uninitialized, T's <i>destructor</i> is called. If <b>*this</b> is initially
|
||||
uninitialized but rhs is initialized, T's <i>copy constructor</i> is called.
|
||||
</p>
|
||||
<p><b>Exception Safety:</b> In the event of an exception, the initialization
|
||||
state of <b>*this</b> is unchanged and its value unspecified as far as optional
|
||||
is concerned (it is up to T's operator=()) [If <b>*this</b> is initially
|
||||
uninitialized and T's <i>copy constructor</i> fails, <b>*this</b> is left
|
||||
properly uninitialized]</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>T v;
|
||||
optional<T> opt(v);
|
||||
optional<T> uninit ;
|
||||
optional<T> def ;
|
||||
|
||||
opt = uninit ;
|
||||
assert ( !opt ) ;
|
||||
opt = def ;
|
||||
assert ( !def ) ;
|
||||
// previous value (copy of 'v') destroyed from within 'opt'.
|
||||
|
||||
</pre>
|
||||
@ -667,6 +718,41 @@ assert ( !opt ) ;
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>optional<T&> & optional<T&>::operator= ( optional<T&> const& rhs ) ;</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> (Re)binds thee wrapped reference.</p>
|
||||
<p><b>Postconditions:</b> If <b>*rhs</b> is initialized, *<b>this</b> is initialized
|
||||
and it references the same object referenced by <b>*rhs</b>; otherwise, <b>*this</b>
|
||||
is uninitialized (and references no object).</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized and so is <b>*rhs</b>, <b>this</b>
|
||||
is is <i>rebound</i> to the new object. See <A HREF="#refassign">here</a> for details on this
|
||||
behavior.</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>int a = 1 ;
|
||||
int b = 2 ;
|
||||
T& ra = a ;
|
||||
T& rb = b ;
|
||||
optional<int&> def ;
|
||||
optional<int&> ora(ra) ;
|
||||
optional<int&> orb(rb) ;
|
||||
|
||||
def = orb ; // binds 'def' to 'b' through 'rb' wrapped within 'orb'
|
||||
assert ( *def == b ) ;
|
||||
*def = ora ; // changes the value of 'b' to a copy of the value of 'a'
|
||||
assert ( b == a ) ;
|
||||
int c = 3;
|
||||
int& rc = c ;
|
||||
optional<int&> orc(rc) ;
|
||||
ora = orc ; // REBINDS ora to 'c' through 'rc'
|
||||
c = 4 ;
|
||||
assert ( *ora == 4 ) ;
|
||||
</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>template<U> optional& optional<T <i>(not a ref)</i>>::operator= ( optional<U> const& rhs ) ;</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> Assigns another <i>convertible</i> <b>optional</b> to an <b>optional</b>.</p>
|
||||
@ -674,14 +760,17 @@ assert ( !opt ) ;
|
||||
and its value is a <i>copy</i> of the value of <b>rhs</b> <i>converted</i>
|
||||
to type T; else <b>*this</b> is uninitialized.
|
||||
</p>
|
||||
<p><b>Throws:</b> Whatever T::T( U const& ) throws.</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, it is first reset to uninitialized
|
||||
using T::~T(), then T::T( U const& ) is called if <b>rhs</b> is initialized,
|
||||
which requires a valid conversion from U to T.
|
||||
</p>
|
||||
<p><b>Exception Safety:</b> <u>Basic:</u> Exceptions can only be thrown during T::T( U const& );
|
||||
in that case, <b>*this</b> is left <u>uninitialized</u>.
|
||||
<p><b>Throws:</b> Whatever T::operator=( U const& ) or T::T( U const& ) throws.</p>
|
||||
<p><b>Notes:</b> If both<b> *this</b> and <b>rhs</b> are initially initialized,
|
||||
T's <i>assignment</i> <i>operator</i> (from U) is used. If <b>*this</b> is initially initialized but <b>
|
||||
rhs</b> is uninitialized, T's <i>destructor</i> is called. If <b>*this</b> is initially
|
||||
uninitialized but rhs is initialized, T's <i>converting constructor</i> (from U) is called.
|
||||
</p>
|
||||
<p><b>Exception Safety:</b> In the event of an exception, the initialization
|
||||
state of <b>*this</b> is unchanged and its value unspecified as far as optional
|
||||
is concerned (it is up to T's operator=()) [If <b>*this</b> is initially
|
||||
uninitialized and T's <i>converting constructor</i> fails, <b>*this</b> is left
|
||||
properly uninitialized]</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>T v;
|
||||
@ -968,7 +1057,7 @@ assert ( optX != optZ ) ;
|
||||
<pre>bool operator > ( optional<T> const& x, optional<T> const& y );
|
||||
</pre>
|
||||
<blockquote>
|
||||
<p><b>Returns:</b> !( y < x );</p>
|
||||
<p><b>Returns:</b> ( y < x );</p>
|
||||
<p><b>Throws:</b> Nothing.</p>
|
||||
</blockquote>
|
||||
|
||||
@ -1105,7 +1194,7 @@ else print("employer's name not found!");
|
||||
|
||||
};
|
||||
</pre>
|
||||
<h3>Bypassing expensive unnecesary default construction</h3>
|
||||
<h3>Bypassing expensive unnecessary default construction</h3>
|
||||
<pre>class ExpensiveCtor { ... } ;
|
||||
class Fred
|
||||
{
|
||||
@ -1118,7 +1207,7 @@ class Fred
|
||||
<HR>
|
||||
|
||||
<H2><A NAME="ref">Optional references</A></H2>
|
||||
<p>This library allow the template parameter T to be of reference type: T&, and
|
||||
<p>This library allows the template parameter T to be of reference type: T&, and
|
||||
to some extent, T const&.</p>
|
||||
|
||||
<p>However, since references are not real objects some restrictions apply and
|
||||
@ -1136,11 +1225,90 @@ value, a true real reference is stored so aliasing will ocurr: </p>
|
||||
|
||||
<ul>
|
||||
<li>Copies of optional<T&> will copy the references but all these references
|
||||
will nonetheless refeer to the same object.</li>
|
||||
will nonetheless reefer to the same object.</li>
|
||||
<li>Value-access will actually provide access to the referenced object rather
|
||||
than the reference itself.</li>
|
||||
</ul>
|
||||
|
||||
<HR>
|
||||
<h2><A NAME="refassign">Rebinding semantics for assignment of optional
|
||||
references</a></h2>
|
||||
<p>If you assign to an <i>uninitialized</i> optional<T&> the effect is to bind (for the first time) to the object.
|
||||
Clearly, there is no other choice.</p>
|
||||
<pre>int x = 1 ;
|
||||
int& rx = x ;
|
||||
optional<int&> ora ;
|
||||
optional<int&> orb(x) ;
|
||||
ora = orb ; // now 'ora' is bound to 'x' through 'rx'
|
||||
*ora = 2 ; // Changes value of 'x' through 'ora'
|
||||
assert(x==2);
|
||||
</pre>
|
||||
<p>If you assign to a bare C++ reference, the assignment is forwarded to the
|
||||
referenced object; it's value changes but the reference is never rebound.</p>
|
||||
<pre>int a = 1 ;
|
||||
int& ra = a ;
|
||||
int b = 2 ;
|
||||
int& rb = b ;
|
||||
ra = rb ; // Changes the value of 'a' to 'b'
|
||||
assert(a==b);
|
||||
b = 3 ;
|
||||
assert(ra!=b); // 'ra' is not rebound to 'b'
|
||||
</pre>
|
||||
<p>Now, if you assign to an <i>initialized</i> optional<T&>, the effect is to <b>
|
||||
rebind</b> to the new object instead of assigning the referee. This is unlike
|
||||
bare C++ references.</p>
|
||||
<pre>int a = 1 ;
|
||||
int b = 2 ;
|
||||
int& ra = a ;
|
||||
int& rb = b ;
|
||||
optional<int&> ora(ra) ;
|
||||
optional<int&> orb(rb) ;
|
||||
ora = orb ; // 'ora' is <b>rebound</b> to 'b'
|
||||
*ora = 3 ; // Changes value of 'b' (not 'a')
|
||||
assert(a==1);
|
||||
assert(b==3);
|
||||
</pre>
|
||||
<h3>Rationale:</h3>
|
||||
<p>Rebinding semantics for the assignment of <i>initialized</i> optional
|
||||
references has been chosen to provide<b><i> </i>consistency among initialization
|
||||
states<i> </i></b>even at the expense of lack of consistency with the semantics of bare
|
||||
C++ references.<br>
|
||||
It is true that optional<U> strives to behave as much as possible as U does
|
||||
whenever it is initialized; but in the case when U is T&, doing so would result
|
||||
in inconsistent behavior w.r.t to the lvalue initialization state.</p>
|
||||
<p>Imagine optional<T&> forwarding assignment to the referenced object (thus
|
||||
changing the referenced object value but not rebinding), and consider the
|
||||
following code :</p>
|
||||
<pre> optional<int&> a = get();
|
||||
int x = 1 ;
|
||||
int& rx = x ;
|
||||
optional<int&> b(rx);
|
||||
a = b ;
|
||||
</pre>
|
||||
<p>What does the assignment do?<br>
|
||||
If 'a' is <i>uninitialized</i>, the answer is clear: it binds to 'x' (we now have
|
||||
another reference to 'x').<br>
|
||||
But what if 'a' is already <i>initialized? </i>it would change the value of the
|
||||
referenced object (whatever that is); which is inconsistent with the other
|
||||
possible case.</p>
|
||||
<p>If optional<T&> would assign just like T& does, you would never be able to
|
||||
use Optional's assignment without explicitly handling the previous
|
||||
initialization state unless your code is capable of functioning whether after
|
||||
the assignment, 'a'
|
||||
aliases the same object as 'b' or not.</p>
|
||||
<p>That is, you would have to discriminate in order to be consistency.<br>
|
||||
<br>
|
||||
If in your code rebinding to another object is not an option, then is very
|
||||
likely that binding for the fist time isn't either. In such case, assignment to
|
||||
an <i>uninitialized</i> optional<T&> shall be prohibited. It is quite
|
||||
possible that in such scenario the precondition that the lvalue must be already
|
||||
initialized exist. If it doesn't, then binding for the first time is OK while
|
||||
rebinding is not which is IMO
|
||||
very unlikely.<br>
|
||||
In such scenario, you can assign the value itself directly, as in:</p>
|
||||
<pre>assert(!!opt);
|
||||
*opt=value; </pre>
|
||||
|
||||
<HR>
|
||||
|
||||
<H2><A NAME="inplace">In-Place Factories</A></H2>
|
||||
@ -1170,7 +1338,7 @@ public:
|
||||
</pre>
|
||||
<p>A solution to this problem is to support direct construction of the contained
|
||||
object right in the container's storage.<br>
|
||||
In this shceme, the user only needs to supply the arguments to the constructor
|
||||
In this scheme, the user only needs to supply the arguments to the constructor
|
||||
to use in the wrapped object construction.</p>
|
||||
<pre>class W
|
||||
{
|
||||
@ -1190,12 +1358,12 @@ public:
|
||||
</pre>
|
||||
<p>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.</p>
|
||||
<p>The solution presented in this library is the familiy of <b>InPlaceFactories</b> and
|
||||
<p>The solution presented in this library is the family of <b>InPlaceFactories</b> and
|
||||
<b>TypedInPlaceFactories</b>.<br>
|
||||
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.</p>
|
||||
<p> For example, one member of this familiy looks like:</p>
|
||||
<p> For example, one member of this family looks like:</p>
|
||||
<pre>template<class T,class A0, class A1>
|
||||
class TypedInPlaceFactory2
|
||||
{
|
||||
@ -1268,10 +1436,10 @@ public:
|
||||
|
||||
<H2><A NAME="bool">A note about optional<bool></A></H2>
|
||||
<p><code>optional<bool></code> should be used with special caution and consideration.</p>
|
||||
<p>First, it is functionally similar to a tristate boolean (false,maybe,true) —such as <u>boost::tribool</u> (not yet formally in boost)—except that in a tristate boolean,
|
||||
<p>First, it is functionally similar to a tristate boolean (false,maybe,true) —such as <a href="http://www.boost.org/doc/html/tribool.html">boost::tribool</a>—except that in a tristate boolean,
|
||||
the <i>maybe</i> state <u>represents a valid value</u>, unlike the corresponding state
|
||||
of an uninitialized optional<bool>.<br>
|
||||
It should be carefully considered if an optional bool instead of a tribool is really needed</p>
|
||||
It should be carefully considered if an optional<bool> instead of a tribool is really needed</p>
|
||||
<p>Second, optional<> provides an implicit conversion to bool. This conversion
|
||||
refers to the initialization state and not to the contained value.<br>
|
||||
Using optional<bool> can lead to subtle errors due to the implicit bool conversion:</p>
|
||||
@ -1432,8 +1600,8 @@ T <u>is not</u> required to be <a href="http://www.sgi.com/tech/stl/DefaultConst
|
||||
</blockquote>
|
||||
<HR>
|
||||
|
||||
<P>Revised Jannuary 30, 2004</P>
|
||||
<p><EFBFBD> Copyright Fernando Luis Cacciola Carballal, 2003,2004</p>
|
||||
<P>Revised April 21, 2005</P>
|
||||
<p><EFBFBD> Copyright Fernando Luis Cacciola Carballal, 2003,2004,2005</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
@ -1443,4 +1611,4 @@ the latest version of this file can be found at <A
|
||||
HREF="http://www.boost.org">www.boost.org</A>, and the boost
|
||||
<A HREF="http://www.boost.org/more/mailing_lists.htm#main">discussion lists</A></P>
|
||||
</BODY>
|
||||
</HTML>
|
||||
</HTML>
|
@ -12,7 +12,7 @@
|
||||
#ifndef BOOST_NONE_17SEP2003_HPP
|
||||
#define BOOST_NONE_17SEP2003_HPP
|
||||
|
||||
#include "boost/detail/none_t.hpp"
|
||||
#include "boost/none_t.hpp"
|
||||
|
||||
// NOTE: Borland users have to include this header outside any precompiled headers
|
||||
// (bcc<=5.64 cannot include instance data in a precompiled header)
|
||||
@ -21,7 +21,7 @@ namespace boost {
|
||||
|
||||
namespace {
|
||||
|
||||
detail::none_t const none = ((detail::none_t)0) ;
|
||||
none_t const none = ((none_t)0) ;
|
||||
|
||||
}
|
||||
|
||||
|
24
include/boost/none_t.hpp
Normal file
24
include/boost/none_t.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
//
|
||||
// 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:
|
||||
// fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NONE_T_17SEP2003_HPP
|
||||
#define BOOST_NONE_T_17SEP2003_HPP
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail { struct none_helper{}; }
|
||||
|
||||
typedef int detail::none_helper::*none_t ;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
@ -26,9 +26,11 @@
|
||||
#include "boost/mpl/bool.hpp"
|
||||
#include "boost/mpl/not.hpp"
|
||||
#include "boost/detail/reference_content.hpp"
|
||||
#include "boost/detail/none_t.hpp"
|
||||
#include "boost/none_t.hpp"
|
||||
#include "boost/utility/compare_pointees.hpp"
|
||||
|
||||
#include "boost/optional/optional_fwd.hpp"
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
|
||||
// VC6.0 has the following bug:
|
||||
// When a templated assignment operator exist, an implicit conversion
|
||||
@ -167,7 +169,7 @@ class optional_base : public optional_tag
|
||||
|
||||
// Creates an optional<T> uninitialized.
|
||||
// No-throw
|
||||
optional_base ( detail::none_t const& )
|
||||
optional_base ( none_t const& )
|
||||
:
|
||||
m_initialized(false) {}
|
||||
|
||||
@ -208,32 +210,57 @@ class optional_base : public optional_tag
|
||||
~optional_base() { destroy() ; }
|
||||
|
||||
// Assigns from another optional<T> (deep-copies the rhs value)
|
||||
// Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED
|
||||
void assign ( optional_base const& rhs )
|
||||
{
|
||||
if (is_initialized())
|
||||
{
|
||||
if ( rhs.is_initialized() )
|
||||
assign_value(rhs.get_impl(), is_reference_predicate() );
|
||||
else destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
destroy();
|
||||
if ( rhs.is_initialized() )
|
||||
construct(rhs.get_impl());
|
||||
}
|
||||
}
|
||||
|
||||
// Assigns from another _convertible_ optional<U> (deep-copies the rhs value)
|
||||
template<class U>
|
||||
void assign ( optional<U> const& rhs )
|
||||
{
|
||||
if (is_initialized())
|
||||
{
|
||||
if ( rhs.is_initialized() )
|
||||
assign_value(static_cast<value_type>(rhs.get()), is_reference_predicate() );
|
||||
else destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rhs.is_initialized() )
|
||||
construct(static_cast<value_type>(rhs.get()));
|
||||
}
|
||||
}
|
||||
|
||||
// Assigns from a T (deep-copies the rhs value)
|
||||
// Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED
|
||||
void assign ( argument_type val )
|
||||
{
|
||||
destroy();
|
||||
construct(val);
|
||||
}
|
||||
{
|
||||
if (is_initialized())
|
||||
assign_value(val, is_reference_predicate() );
|
||||
else construct(val);
|
||||
}
|
||||
|
||||
// Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED
|
||||
// No-throw (assuming T::~T() doesn't)
|
||||
void assign ( detail::none_t const& ) { destroy(); }
|
||||
void assign ( none_t const& ) { destroy(); }
|
||||
|
||||
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
|
||||
template<class Expr>
|
||||
void assign_expr ( Expr const& expr, Expr const* tag )
|
||||
{
|
||||
destroy();
|
||||
construct(expr,tag);
|
||||
if (is_initialized())
|
||||
assign_expr_to_initialized(expr,tag);
|
||||
else construct(expr,tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -244,7 +271,6 @@ class optional_base : public optional_tag
|
||||
void reset() { destroy(); }
|
||||
|
||||
// Replaces the current value -if any- with 'val'
|
||||
// Basic Guarantee: If T::T( T const& ) throws this is left UNINITIALIZED.
|
||||
void reset ( argument_type val ) { assign(val); }
|
||||
|
||||
// Returns a pointer to the value if this is initialized, otherwise,
|
||||
@ -281,6 +307,21 @@ class optional_base : public optional_tag
|
||||
factory.apply(m_storage.address()) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag )
|
||||
{
|
||||
destroy();
|
||||
construct(factory,tag);
|
||||
}
|
||||
|
||||
// Constructs in-place using the given typed factory
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag )
|
||||
{
|
||||
destroy();
|
||||
construct(factory,tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Constructs using any expression implicitely convertible to the single argument
|
||||
@ -294,6 +335,16 @@ class optional_base : public optional_tag
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
// Assigns using a form any expression implicitely convertible to the single argument
|
||||
// of a T's assignment operator.
|
||||
// Converting assignments of optional<T> from optional<U> uses this function with
|
||||
// 'Expr' being of type 'U' and relying on a converting assignment of T from U.
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& expr, void const* )
|
||||
{
|
||||
assign_value(expr, is_reference_predicate());
|
||||
}
|
||||
|
||||
#ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
|
||||
// BCB5.64 (and probably lower versions) workaround.
|
||||
// The in-place factories are supported by means of catch-all constructors
|
||||
@ -321,11 +372,14 @@ class optional_base : public optional_tag
|
||||
}
|
||||
#endif
|
||||
|
||||
void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; }
|
||||
void assign_value ( argument_type val, is_reference_tag ) { construct(val); }
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if ( m_initialized )
|
||||
destroy_impl(is_reference_predicate()) ;
|
||||
}
|
||||
{
|
||||
if ( m_initialized )
|
||||
destroy_impl(is_reference_predicate()) ;
|
||||
}
|
||||
|
||||
unspecified_bool_type safe_bool() const { return m_initialized ? &this_type::is_initialized : 0 ; }
|
||||
|
||||
@ -391,7 +445,7 @@ class optional : public optional_detail::optional_base<T>
|
||||
|
||||
// Creates an optional<T> uninitialized.
|
||||
// No-throw
|
||||
optional( detail::none_t const& none_ ) : base(none_) {}
|
||||
optional( none_t const& none_ ) : base(none_) {}
|
||||
|
||||
// Creates an optional<T> initialized with 'val'.
|
||||
// Can throw if T::T(T const&) does
|
||||
@ -446,6 +500,7 @@ class optional : public optional_detail::optional_base<T>
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT
|
||||
// Assigns from another convertible optional<U> (converts && deep-copies the rhs value)
|
||||
// Requires a valid conversion from U to T.
|
||||
@ -453,14 +508,7 @@ class optional : public optional_detail::optional_base<T>
|
||||
template<class U>
|
||||
optional& operator= ( optional<U> const& rhs )
|
||||
{
|
||||
this->destroy(); // no-throw
|
||||
|
||||
if ( rhs.is_initialized() )
|
||||
{
|
||||
// An exception can be thrown here.
|
||||
// It it happens, THIS will be left uninitialized.
|
||||
this->assign(rhs.get());
|
||||
}
|
||||
this->assign(rhs);
|
||||
return *this ;
|
||||
}
|
||||
#endif
|
||||
@ -485,7 +533,7 @@ class optional : public optional_detail::optional_base<T>
|
||||
// Assigns from a "none"
|
||||
// Which destroys the current value, if any, leaving this UNINITIALIZED
|
||||
// No-throw (assuming T::~T() doesn't)
|
||||
optional& operator= ( detail::none_t const& none_ )
|
||||
optional& operator= ( none_t const& none_ )
|
||||
{
|
||||
this->assign( none_ ) ;
|
||||
return *this ;
|
||||
@ -607,62 +655,62 @@ bool operator >= ( optional<T> const& x, optional<T> const& y )
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator == ( optional<T> const& x, detail::none_t const& )
|
||||
bool operator == ( optional<T> const& x, none_t const& )
|
||||
{ return equal_pointees(x, optional<T>() ); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator < ( optional<T> const& x, detail::none_t const& )
|
||||
bool operator < ( optional<T> const& x, none_t const& )
|
||||
{ return less_pointees(x,optional<T>() ); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator != ( optional<T> const& x, detail::none_t const& y )
|
||||
bool operator != ( optional<T> const& x, none_t const& y )
|
||||
{ return !( x == y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator > ( optional<T> const& x, detail::none_t const& y )
|
||||
bool operator > ( optional<T> const& x, none_t const& y )
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator <= ( optional<T> const& x, detail::none_t const& y )
|
||||
bool operator <= ( optional<T> const& x, none_t const& y )
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator >= ( optional<T> const& x, detail::none_t const& y )
|
||||
bool operator >= ( optional<T> const& x, none_t const& y )
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator == ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator == ( none_t const& x, optional<T> const& y )
|
||||
{ return equal_pointees(optional<T>() ,y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator < ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator < ( none_t const& x, optional<T> const& y )
|
||||
{ return less_pointees(optional<T>() ,y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator != ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator != ( none_t const& x, optional<T> const& y )
|
||||
{ return !( x == y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator > ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator > ( none_t const& x, optional<T> const& y )
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator <= ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator <= ( none_t const& x, optional<T> const& y )
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator >= ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator >= ( none_t const& x, optional<T> const& y )
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
//
|
||||
@ -679,8 +727,9 @@ namespace optional_detail {
|
||||
#endif
|
||||
|
||||
// optional's swap:
|
||||
// If both are initialized, calls swap(T&, T&), with whatever exception guarantess are given there.
|
||||
// If only one is initialized, calls I.reset() and U.reset(*I), with the Basic Guarantee
|
||||
// If both are initialized, calls swap(T&, T&). If this swap throws, both will remain initialized but their values are now unspecified.
|
||||
// If only one is initialized, calls U.reset(*I), THEN I.reset().
|
||||
// If U.reset(*I) throws, both are left UNCHANGED (U is kept uinitialized and I is never reset)
|
||||
// If both are uninitialized, do nothing (no-throw)
|
||||
template<class T>
|
||||
inline
|
||||
@ -688,12 +737,12 @@ void optional_swap ( optional<T>& x, optional<T>& y )
|
||||
{
|
||||
if ( !x && !!y )
|
||||
{
|
||||
x.reset(*y); // Basic guarantee.
|
||||
x.reset(*y);
|
||||
y.reset();
|
||||
}
|
||||
else if ( !!x && !y )
|
||||
{
|
||||
y.reset(*x); // Basic guarantee.
|
||||
y.reset(*x);
|
||||
x.reset();
|
||||
}
|
||||
else if ( !!x && !!y )
|
||||
@ -714,6 +763,11 @@ template<class T> inline void swap ( optional<T>& x, optional<T>& y )
|
||||
optional_detail::optional_swap(x,y);
|
||||
}
|
||||
|
||||
template<class T> inline optional<T> make_optional ( T const& v )
|
||||
{
|
||||
return optional<T>(v);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
@ -70,7 +70,7 @@ void test_basics( T const* )
|
||||
// Implicit construction
|
||||
// The first parameter is implicitely converted to optional<T>(a);
|
||||
test_implicit_construction(a,a,z);
|
||||
|
||||
|
||||
// Direct initialization.
|
||||
// 'oa' state is Initialized with 'a'
|
||||
// T::T( T const& x ) is used.
|
||||
@ -85,7 +85,7 @@ void test_basics( T const* )
|
||||
optional<T> ob ;
|
||||
|
||||
// Value-Assignment upon Uninitialized optional.
|
||||
// T::T ( T const& x ) is used.
|
||||
// T::T( T const& x ) is used.
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
ob = a ;
|
||||
check_is_not_pending_copy( ARG(T) ) ;
|
||||
@ -93,12 +93,14 @@ void test_basics( T const* )
|
||||
check_value(ob,a,z);
|
||||
|
||||
// Value-Assignment upon Initialized optional.
|
||||
// T::T ( T const& x ) is used
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
// T::operator=( T const& x ) is used
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
set_pending_copy ( ARG(T) ) ;
|
||||
set_pending_dtor ( ARG(T) ) ;
|
||||
ob = b ;
|
||||
check_is_not_pending_dtor( ARG(T) ) ;
|
||||
check_is_not_pending_copy( ARG(T) ) ;
|
||||
check_is_not_pending_assign( ARG(T) ) ;
|
||||
check_is_pending_copy ( ARG(T) ) ;
|
||||
check_is_pending_dtor ( ARG(T) ) ;
|
||||
check_initialized(ob);
|
||||
check_value(ob,b,z);
|
||||
|
||||
@ -111,13 +113,14 @@ void test_basics( T const* )
|
||||
check_value_const(oa2,a,z);
|
||||
|
||||
// Assignment
|
||||
// T::~T() is used to destroy previous value in ob.
|
||||
// T::T ( T const& x ) is used to copy new value.
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
// T::operator= ( T const& x ) is used to copy new value.
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
set_pending_copy ( ARG(T) ) ;
|
||||
set_pending_dtor ( ARG(T) ) ;
|
||||
oa = ob ;
|
||||
check_is_not_pending_dtor( ARG(T) ) ;
|
||||
check_is_not_pending_copy( ARG(T) ) ;
|
||||
check_is_not_pending_assign( ARG(T) ) ;
|
||||
check_is_pending_copy ( ARG(T) ) ;
|
||||
check_is_pending_dtor ( ARG(T) ) ;
|
||||
check_initialized(oa);
|
||||
check_value(oa,b,z);
|
||||
|
||||
@ -161,7 +164,7 @@ template<class T>
|
||||
void test_direct_value_manip( T const* )
|
||||
{
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
|
||||
T x(3);
|
||||
|
||||
optional<T> const c_opt0(x) ;
|
||||
@ -169,7 +172,7 @@ void test_direct_value_manip( T const* )
|
||||
|
||||
BOOST_CHECK( c_opt0.get().V() == x.V() ) ;
|
||||
BOOST_CHECK( opt0.get().V() == x.V() ) ;
|
||||
|
||||
|
||||
BOOST_CHECK( c_opt0->V() == x.V() ) ;
|
||||
BOOST_CHECK( opt0->V() == x.V() ) ;
|
||||
|
||||
@ -212,7 +215,7 @@ void test_uninitialized_access( T const* )
|
||||
}
|
||||
catch (...) {}
|
||||
BOOST_CHECK(!passed);
|
||||
|
||||
|
||||
passed = false ;
|
||||
try
|
||||
{
|
||||
@ -282,6 +285,9 @@ void test_throwing_direct_init( T const* )
|
||||
BOOST_CHECK(!passed);
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
@ -317,6 +323,8 @@ void test_throwing_val_assign_on_uninitialized( T const* )
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
check_uninitialized(opt);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -330,11 +338,10 @@ void test_throwing_val_assign_on_initialized( T const* )
|
||||
T z(0);
|
||||
T a(8);
|
||||
T b(9);
|
||||
T x(-1);
|
||||
|
||||
int count = get_instance_count( ARG(T) ) ;
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
optional<T> opt ( b ) ;
|
||||
++ count ;
|
||||
|
||||
@ -342,16 +349,16 @@ void test_throwing_val_assign_on_initialized( T const* )
|
||||
|
||||
check_value(opt,b,z);
|
||||
|
||||
set_throw_on_copy( ARG(T) ) ;
|
||||
set_throw_on_assign( ARG(T) ) ;
|
||||
|
||||
bool passed = false ;
|
||||
try
|
||||
{
|
||||
// This should:
|
||||
// Attempt to copy construct 'a' and throw.
|
||||
// opt should be left uninitialized (even though it was initialized)
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
// Attempt to assign 'a' and throw.
|
||||
// opt is kept initialized but its value not neccesarily fully assigned
|
||||
// (in this test, incompletely assigned is flaged with the value -1 being set)
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
opt.reset ( a ) ;
|
||||
passed = true ;
|
||||
}
|
||||
@ -359,12 +366,12 @@ void test_throwing_val_assign_on_initialized( T const* )
|
||||
|
||||
BOOST_CHECK(!passed);
|
||||
|
||||
-- count ;
|
||||
|
||||
check_is_not_pending_dtor( ARG(T) );
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_is_not_pending_assign( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
check_uninitialized(opt);
|
||||
check_initialized(opt);
|
||||
check_value(opt,x,z);
|
||||
|
||||
reset_throw_on_assign ( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -378,8 +385,6 @@ void test_throwing_copy_initialization( T const* )
|
||||
T z(0);
|
||||
T a(10);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
optional<T> opt (a);
|
||||
|
||||
int count = get_instance_count( ARG(T) ) ;
|
||||
@ -406,6 +411,8 @@ void test_throwing_copy_initialization( T const* )
|
||||
// Nothing should have happened to the source optional.
|
||||
check_initialized(opt);
|
||||
check_value(opt,a,z);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -420,8 +427,6 @@ void test_throwing_assign_to_uninitialized( T const* )
|
||||
T z(0);
|
||||
T a(11);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
optional<T> opt0 ;
|
||||
optional<T> opt1(a) ;
|
||||
|
||||
@ -446,6 +451,8 @@ void test_throwing_assign_to_uninitialized( T const* )
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
check_uninitialized(opt0);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -460,24 +467,23 @@ void test_throwing_assign_to_initialized( T const* )
|
||||
T z(0);
|
||||
T a(12);
|
||||
T b(13);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
T x(-1);
|
||||
|
||||
optional<T> opt0(a) ;
|
||||
optional<T> opt1(b) ;
|
||||
|
||||
int count = get_instance_count( ARG(T) ) ;
|
||||
|
||||
set_throw_on_copy( ARG(T) ) ;
|
||||
set_throw_on_assign( ARG(T) ) ;
|
||||
|
||||
bool passed = false ;
|
||||
try
|
||||
{
|
||||
// This should:
|
||||
// Attempt to copy construct 'opt1.value()' into opt0 and throw.
|
||||
// opt0 should be left unmodified or uninitialized
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
// opt0 is kept initialized but its value not neccesarily fully assigned
|
||||
// (in this test, incompletely assigned is flaged with the value -1 being set)
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
opt0 = opt1 ;
|
||||
passed = true ;
|
||||
}
|
||||
@ -486,11 +492,12 @@ void test_throwing_assign_to_initialized( T const* )
|
||||
BOOST_CHECK(!passed);
|
||||
|
||||
// opt0 was left uninitialized
|
||||
-- count ;
|
||||
check_is_not_pending_dtor( ARG(T) );
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_is_not_pending_assign( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
check_uninitialized(opt0);
|
||||
check_initialized(opt0);
|
||||
check_value(opt0,x,z);
|
||||
|
||||
reset_throw_on_assign( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -500,13 +507,11 @@ template<class T>
|
||||
void test_no_throwing_swap( T const* )
|
||||
{
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
|
||||
T z(0);
|
||||
T a(14);
|
||||
T b(15);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
optional<T> def0 ;
|
||||
optional<T> def1 ;
|
||||
optional<T> opt0(a) ;
|
||||
@ -541,16 +546,15 @@ template<class T>
|
||||
void test_throwing_swap( T const* )
|
||||
{
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
|
||||
T a(16);
|
||||
T b(17);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
T x(-1);
|
||||
|
||||
optional<T> opt0(a) ;
|
||||
optional<T> opt1(b) ;
|
||||
|
||||
set_throw_on_copy( ARG(T) ) ;
|
||||
set_throw_on_assign( ARG(T) ) ;
|
||||
|
||||
//
|
||||
// Case 1: Both Initialized.
|
||||
@ -567,14 +571,18 @@ void test_throwing_swap( T const* )
|
||||
|
||||
BOOST_CHECK(!passed);
|
||||
|
||||
// Assuming swap(T&,T&) has at least the basic guarantee, these should hold.
|
||||
BOOST_CHECK( ( !opt0 || ( !!opt0 && ( ( *opt0 == a ) || ( *opt0 == b ) ) ) ) ) ;
|
||||
BOOST_CHECK( ( !opt1 || ( !!opt1 && ( ( *opt1 == a ) || ( *opt1 == b ) ) ) ) ) ;
|
||||
// optional's swap doesn't affect the initialized states of the arguments. Therefore,
|
||||
// the following must hold:
|
||||
check_initialized(opt0);
|
||||
check_initialized(opt1);
|
||||
check_value(opt0,x,a);
|
||||
check_value(opt1,b,x);
|
||||
|
||||
|
||||
//
|
||||
// Case 2: Only one Initialized.
|
||||
//
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
reset_throw_on_assign( ARG(T) ) ;
|
||||
|
||||
opt0.reset();
|
||||
opt1.reset(a);
|
||||
@ -585,7 +593,7 @@ void test_throwing_swap( T const* )
|
||||
try
|
||||
{
|
||||
// This should attempt to swap optionals and fail at opt0.reset(*opt1)
|
||||
// opt0 should be left uninitialized and opt1 unchanged.
|
||||
// Both opt0 and op1 are left unchanged (unswaped)
|
||||
swap(opt0,opt1);
|
||||
|
||||
passed = true ;
|
||||
@ -596,7 +604,9 @@ void test_throwing_swap( T const* )
|
||||
|
||||
check_uninitialized(opt0);
|
||||
check_initialized(opt1);
|
||||
check_value(opt1,a,b);
|
||||
check_value(opt1,a,x);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -606,9 +616,7 @@ template<class T>
|
||||
void test_relops( T const* )
|
||||
{
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
|
||||
T v0(18);
|
||||
T v1(19);
|
||||
T v2(19);
|
||||
@ -627,11 +635,11 @@ void test_relops( T const* )
|
||||
|
||||
// Check when both are uininitalized.
|
||||
BOOST_CHECK ( def0 == def1 ) ; // both uninitialized compare equal
|
||||
BOOST_CHECK ( !(def0 < def1) ) ; // uninitialized is never less than uninitialized
|
||||
BOOST_CHECK ( !(def0 < def1) ) ; // uninitialized is never less than uninitialized
|
||||
BOOST_CHECK ( !(def0 > def1) ) ; // uninitialized is never greater than uninitialized
|
||||
BOOST_CHECK ( !(def0 != def1) ) ;
|
||||
BOOST_CHECK ( def0 <= def1 ) ;
|
||||
BOOST_CHECK ( def0 >= def1 ) ;
|
||||
BOOST_CHECK ( def0 <= def1 ) ;
|
||||
BOOST_CHECK ( def0 >= def1 ) ;
|
||||
|
||||
// Check when only lhs is uninitialized.
|
||||
BOOST_CHECK ( def0 != opt0 ) ; // uninitialized is never equal to initialized
|
||||
@ -664,7 +672,7 @@ void test_none( T const* )
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
using boost::none ;
|
||||
|
||||
|
||||
optional<T> def0 ;
|
||||
optional<T> def1(none) ;
|
||||
optional<T> non_def( T(1234) ) ;
|
||||
@ -682,7 +690,7 @@ void test_none( T const* )
|
||||
void test_with_builtin_types()
|
||||
{
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
|
||||
test_basics( ARG(double) );
|
||||
test_uninitialized_access( ARG(double) );
|
||||
test_no_throwing_swap( ARG(double) );
|
||||
@ -763,7 +771,7 @@ void test_conversions1()
|
||||
optional<double> opt3 ;
|
||||
opt3 = opt2 ;
|
||||
BOOST_CHECK(*opt3 == d);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_conversions2()
|
||||
|
@ -93,10 +93,22 @@ class X
|
||||
|
||||
X& operator= ( X const& rhs )
|
||||
{
|
||||
v = rhs.v ;
|
||||
pending_assign = false ;
|
||||
|
||||
TRACE ( "X::operator =( X const& rhs). this=" << this << " rhs.v=" << rhs.v ) ;
|
||||
if ( throw_on_assign )
|
||||
{
|
||||
TRACE ( "throwing exception in X's assignment" ) ;
|
||||
|
||||
v = -1 ;
|
||||
|
||||
throw 0 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = rhs.v ;
|
||||
|
||||
TRACE ( "X::operator =( X const& rhs). this=" << this << " rhs.v=" << rhs.v ) ;
|
||||
}
|
||||
return *this ;
|
||||
}
|
||||
|
||||
@ -115,7 +127,9 @@ class X
|
||||
static int count ;
|
||||
static bool pending_copy ;
|
||||
static bool pending_dtor ;
|
||||
static bool pending_assign ;
|
||||
static bool throw_on_copy ;
|
||||
static bool throw_on_assign ;
|
||||
|
||||
private :
|
||||
|
||||
@ -127,32 +141,44 @@ class X
|
||||
} ;
|
||||
|
||||
|
||||
int X::count = 0 ;
|
||||
bool X::pending_copy = false ;
|
||||
bool X::pending_dtor = false ;
|
||||
bool X::throw_on_copy = false ;
|
||||
int X::count = 0 ;
|
||||
bool X::pending_copy = false ;
|
||||
bool X::pending_dtor = false ;
|
||||
bool X::pending_assign = false ;
|
||||
bool X::throw_on_copy = false ;
|
||||
bool X::throw_on_assign = false ;
|
||||
|
||||
inline void set_pending_copy ( X const* x ) { X::pending_copy = true ; }
|
||||
inline void set_pending_dtor ( X const* x ) { X::pending_dtor = true ; }
|
||||
inline void set_throw_on_copy ( X const* x ) { X::throw_on_copy = true ; }
|
||||
inline void reset_throw_on_copy ( X const* x ) { X::throw_on_copy = false ; }
|
||||
inline void check_is_pending_copy ( X const* x ) { BOOST_CHECK( X::pending_copy ) ; }
|
||||
inline void check_is_pending_dtor ( X const* x ) { BOOST_CHECK( X::pending_dtor ) ; }
|
||||
inline void check_is_not_pending_copy( X const* x ) { BOOST_CHECK( !X::pending_copy ) ; }
|
||||
inline void check_is_not_pending_dtor( X const* x ) { BOOST_CHECK( !X::pending_dtor ) ; }
|
||||
inline void check_instance_count ( int c, X const* x ) { BOOST_CHECK( X::count == c ) ; }
|
||||
inline int get_instance_count ( X const* x ) { return X::count ; }
|
||||
inline void set_pending_copy ( X const* x ) { X::pending_copy = true ; }
|
||||
inline void set_pending_dtor ( X const* x ) { X::pending_dtor = true ; }
|
||||
inline void set_pending_assign ( X const* x ) { X::pending_assign = true ; }
|
||||
inline void set_throw_on_copy ( X const* x ) { X::throw_on_copy = true ; }
|
||||
inline void set_throw_on_assign ( X const* x ) { X::throw_on_assign = true ; }
|
||||
inline void reset_throw_on_copy ( X const* x ) { X::throw_on_copy = false ; }
|
||||
inline void reset_throw_on_assign ( X const* x ) { X::throw_on_assign = false ; }
|
||||
inline void check_is_pending_copy ( X const* x ) { BOOST_CHECK( X::pending_copy ) ; }
|
||||
inline void check_is_pending_dtor ( X const* x ) { BOOST_CHECK( X::pending_dtor ) ; }
|
||||
inline void check_is_pending_assign ( X const* x ) { BOOST_CHECK( X::pending_assign ) ; }
|
||||
inline void check_is_not_pending_copy ( X const* x ) { BOOST_CHECK( !X::pending_copy ) ; }
|
||||
inline void check_is_not_pending_dtor ( X const* x ) { BOOST_CHECK( !X::pending_dtor ) ; }
|
||||
inline void check_is_not_pending_assign( X const* x ) { BOOST_CHECK( !X::pending_assign ) ; }
|
||||
inline void check_instance_count ( int c, X const* x ) { BOOST_CHECK( X::count == c ) ; }
|
||||
inline int get_instance_count ( X const* x ) { return X::count ; }
|
||||
|
||||
inline void set_pending_copy (...) {}
|
||||
inline void set_pending_dtor (...) {}
|
||||
inline void set_throw_on_copy (...) {}
|
||||
inline void reset_throw_on_copy (...) {}
|
||||
inline void check_is_pending_copy (...) {}
|
||||
inline void check_is_pending_dtor (...) {}
|
||||
inline void check_is_not_pending_copy(...) {}
|
||||
inline void check_is_not_pending_dtor(...) {}
|
||||
inline void check_instance_count (...) {}
|
||||
inline int get_instance_count (...) { return 0 ; }
|
||||
inline void set_pending_copy (...) {}
|
||||
inline void set_pending_dtor (...) {}
|
||||
inline void set_pending_assign (...) {}
|
||||
inline void set_throw_on_copy (...) {}
|
||||
inline void set_throw_on_assign (...) {}
|
||||
inline void reset_throw_on_copy (...) {}
|
||||
inline void reset_throw_on_assign (...) {}
|
||||
inline void check_is_pending_copy (...) {}
|
||||
inline void check_is_pending_dtor (...) {}
|
||||
inline void check_is_pending_assign (...) {}
|
||||
inline void check_is_not_pending_copy (...) {}
|
||||
inline void check_is_not_pending_dtor (...) {}
|
||||
inline void check_is_not_pending_assign(...) {}
|
||||
inline void check_instance_count (...) {}
|
||||
inline int get_instance_count (...) { return 0 ; }
|
||||
|
||||
|
||||
template<class T>
|
||||
@ -160,7 +186,7 @@ inline void check_uninitialized_const ( optional<T> const& opt )
|
||||
{
|
||||
#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE
|
||||
BOOST_CHECK( opt == 0 ) ;
|
||||
#endif
|
||||
#endif
|
||||
BOOST_CHECK( !opt ) ;
|
||||
BOOST_CHECK( !get_pointer(opt) ) ;
|
||||
BOOST_CHECK( !opt.get_ptr() ) ;
|
||||
|
@ -32,7 +32,7 @@ inline void check_ref_uninitialized_const ( optional<T&> const& opt )
|
||||
{
|
||||
#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE
|
||||
BOOST_CHECK( opt == 0 ) ;
|
||||
#endif
|
||||
#endif
|
||||
BOOST_CHECK( !opt ) ;
|
||||
}
|
||||
template<class T>
|
||||
@ -104,9 +104,16 @@ void test_basics( T const* )
|
||||
|
||||
T z(0);
|
||||
|
||||
T original_a(1);
|
||||
|
||||
T a(1);
|
||||
|
||||
T b(2);
|
||||
|
||||
T c(10);
|
||||
|
||||
T& aref = a ;
|
||||
T& bref = b ;
|
||||
|
||||
// Default construction.
|
||||
// 'def' state is Uninitialized.
|
||||
@ -115,13 +122,16 @@ void test_basics( T const* )
|
||||
check_ref_uninitialized(def);
|
||||
|
||||
// Direct initialization.
|
||||
// 'oa' state is Initialized with 'a'
|
||||
// 'oa' state is Initialized and binds to 'a'
|
||||
// T::T( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
optional<T&> oa ( aref ) ;
|
||||
check_is_pending_copy( ARG(T) );
|
||||
check_ref_initialized(oa);
|
||||
check_ref_value(oa,a,z);
|
||||
*oa = b ; // changes the value of 'a' through the reference
|
||||
BOOST_CHECK( a == b ) ;
|
||||
|
||||
|
||||
// Copy initialization.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
@ -130,27 +140,32 @@ void test_basics( T const* )
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
check_ref_initialized_const(oa2);
|
||||
check_ref_value_const(oa2,a,z);
|
||||
*oa2 = original_a ; // restores the value of 'a' through the reference
|
||||
BOOST_CHECK( a == original_a ) ;
|
||||
|
||||
T b(2);
|
||||
optional<T&> ob ;
|
||||
|
||||
// Value-Assignment upon Uninitialized optional.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
ob = a ;
|
||||
ob = a ; // Binds ob to a temporary non-const refererence to 'a'
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
check_ref_initialized(ob);
|
||||
check_ref_value(ob,a,z);
|
||||
a = c;
|
||||
check_ref_value(ob,a,z);
|
||||
|
||||
// Value-Assignment upon Initialized optional.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
ob = b ;
|
||||
check_is_pending_dtor( ARG(T) ) ;
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
// T::operator= ( T const& x ) is used.
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
ob = b ; // Rebinds 'ob' to 'b' (without changing 'a')
|
||||
check_is_pending_assign( ARG(T) ) ;
|
||||
check_ref_initialized(ob);
|
||||
check_ref_value(ob,b,z);
|
||||
BOOST_CHECK(a == c); // From a=c in previous test
|
||||
b = c;
|
||||
check_ref_value(ob,b,z);
|
||||
|
||||
|
||||
// Assignment initialization.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
@ -162,14 +177,12 @@ void test_basics( T const* )
|
||||
|
||||
|
||||
// Assignment
|
||||
// T::~T() is used to destroy previous value in ob.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
oa = ob ;
|
||||
check_is_pending_dtor( ARG(T) ) ;
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
// T::operator=( T const& x ) is used.
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
oa = ob ; // Rebinds 'a' to 'b'
|
||||
check_is_pending_assign( ARG(T) ) ;
|
||||
check_ref_initialized(oa);
|
||||
a = original_a ;
|
||||
check_ref_value(oa,b,z);
|
||||
|
||||
// Uninitializing Assignment upon Initialized Optional
|
||||
@ -190,6 +203,7 @@ void test_basics( T const* )
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
check_ref_uninitialized(oa);
|
||||
|
||||
|
||||
// Deinitialization of Initialized Optional
|
||||
// T::~T() is NOT used becasue the optional holds a reference.
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
@ -212,9 +226,9 @@ template<class T>
|
||||
void test_relops( T const* )
|
||||
{
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
|
||||
T v0(18);
|
||||
T v1(19);
|
||||
T v2(19);
|
||||
@ -233,11 +247,11 @@ void test_relops( T const* )
|
||||
|
||||
// Check when both are uininitalized.
|
||||
BOOST_CHECK ( def0 == def1 ) ; // both uninitialized compare equal
|
||||
BOOST_CHECK ( !(def0 < def1) ) ; // uninitialized is never less than uninitialized
|
||||
BOOST_CHECK ( !(def0 > def1) ) ; // uninitialized is never greater than uninitialized
|
||||
BOOST_CHECK ( !(def0 < def1) ) ; // uninitialized is never less than uninitialized
|
||||
BOOST_CHECK ( !(def0 > def1) ) ; // uninitialized is never greater than uninitialized
|
||||
BOOST_CHECK ( !(def0 != def1) ) ;
|
||||
BOOST_CHECK ( def0 <= def1 ) ;
|
||||
BOOST_CHECK ( def0 >= def1 ) ;
|
||||
BOOST_CHECK ( def0 <= def1 ) ;
|
||||
BOOST_CHECK ( def0 >= def1 ) ;
|
||||
|
||||
// Check when only lhs is uninitialized.
|
||||
BOOST_CHECK ( def0 != opt0 ) ; // uninitialized is never equal to initialized
|
||||
@ -254,7 +268,7 @@ void test_relops( T const* )
|
||||
BOOST_CHECK ( opt0 > def0 ) ;
|
||||
BOOST_CHECK ( !(opt0 <= def0) ) ;
|
||||
BOOST_CHECK ( opt0 >= opt0 ) ;
|
||||
|
||||
|
||||
// If both are initialized, values are compared
|
||||
BOOST_CHECK ( opt0 != opt1 ) ;
|
||||
BOOST_CHECK ( opt1 == opt2 ) ;
|
||||
@ -270,7 +284,7 @@ void test_none( T const* )
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
using boost::none ;
|
||||
|
||||
|
||||
T a(1234);
|
||||
|
||||
optional<T&> def0 ;
|
||||
|
Reference in New Issue
Block a user