mirror of
https://github.com/boostorg/optional.git
synced 2025-07-16 22:02:07 +02:00
1614 lines
63 KiB
HTML
1614 lines
63 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//SoftQuad Software//DTD HoTMetaL PRO 5.0::19981217::extensions to HTML 4.0//EN" "hmpro5.dtd">
|
||
|
||
<HTML>
|
||
|
||
<HEAD>
|
||
<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>
|
||
|
||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#800080">
|
||
<H2><IMG SRC="../../../boost.png" WIDTH="276" HEIGHT="86">Header <<A
|
||
HREF="../../../boost/optional/optional.hpp">boost/optional/optional.hpp</A>> </H2>
|
||
|
||
<H2>Contents</H2>
|
||
<DL CLASS="page-index">
|
||
<DT><A HREF="#mot">Motivation</A></DT>
|
||
<DT><A HREF="#dev">Development</A></DT>
|
||
<DT><A HREF="#synopsis">Synopsis</A></DT>
|
||
<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>
|
||
<DT><A HREF="#requirements">Type requirements</A></DT>
|
||
<DT><A HREF="#impl">Implementation Notes</A></DT>
|
||
<DT><A HREF="#porta">Dependencies and Portability</A></DT>
|
||
<DT><A HREF="#credits">Acknowledgment</A></DT>
|
||
</DL>
|
||
|
||
<HR>
|
||
|
||
<H2><A NAME="mot"></A>Motivation</H2>
|
||
|
||
<P>Consider these functions which should return a value but which might not have
|
||
a value to return:</P>
|
||
<pre>(A) double sqrt(double n );
|
||
(B) char get_async_input();
|
||
(C) point polygon::get_any_point_effectively_inside();</pre>
|
||
<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 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.</P>
|
||
<P>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.</P>
|
||
<P>A similar situation occurs with function (C): it is conceptually an error to
|
||
ask a <i>null-area</i> 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.</P>
|
||
<P>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...</P>
|
||
<P>When those values exist, i.e. the return type can hold all meaningful values
|
||
<i>plus</i> the <i>signal</i> 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>.
|
||
</P>
|
||
<P>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:</P>
|
||
<pre>std::pair<char,bool> get_async_input();
|
||
std::pair<point,bool> polygon::get_any_point_effectively_inside();</pre>
|
||
<p>These functions use a consistent interface for dealing with possibly inexistent
|
||
results:</p>
|
||
<pre>std::pair<point,bool> p = poly.get_any_point_effectively_inside();
|
||
if ( p.second )
|
||
flood_fill(p.first);
|
||
</pre>
|
||
|
||
<P>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.</P>
|
||
<P>Clearly, we need a better idiom.</P>
|
||
|
||
<H2><A NAME="dev"></A>Development</H2>
|
||
|
||
<h3><u>The models:</u></h3>
|
||
<P>In C++, we can <i>declare</i> an object (a variable) of type T, and we can give this variable
|
||
an <i>initial value</i> (through an <i>initializer</i>. (c.f. 8.5)).<br>
|
||
When a declaration includes a non-empty initializer (an initial value is given), it is said that
|
||
the object has been <i><b>initialized</b></i>.<br>
|
||
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 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 behavior. That is,
|
||
when a variable is declared as optional<T> and no initial value is given,
|
||
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
|
||
means that objects always have an initial value even if indeterminate.<br>
|
||
As discussed on the previous section, this has a drawback because you need additional
|
||
information to tell if an object has been effectively initialized.<br>
|
||
One of the typical ways in which this has been historically
|
||
dealt with is via a special value: EOF,npos,-1, etc... This is equivalent to adding
|
||
the special value to the set of possible values of a given type. This super set of
|
||
T plus some <i>nil_t</i>—were nil_t is some stateless POD-can be modeled in modern
|
||
languages as a <b>discriminated union</b> of <code>T</code> and <code>nil_t</code>.
|
||
Discriminated unions are often called <i>variants</i>. A variant has a <i>current type</i>,
|
||
which in our case is either <code>T</code> or <code>nil_t</code>.<br>
|
||
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> 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
|
||
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 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>
|
||
<p>In any event, both the discriminated-union or the single-element container models serve as a conceptual
|
||
ground for a class representing optional—i.e. possibly uninitialized—objects.<br>
|
||
For instance, these models show the <i>exact</i> semantics required for a wrapper of optional values:</p>
|
||
<p>Discriminated-union:</p>
|
||
<blockquote>
|
||
<li><b>deep-copy</b> semantics: copies of the variant implies copies of the value.</li>
|
||
<li><b>deep-relational</b> semantics: comparisons between variants matches both current types and values</li>
|
||
<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
|
||
behavior
|
||
of trying to access the value of an uninitialized optional</li>
|
||
</blockquote>
|
||
<p>Single-element container:</p>
|
||
<blockquote>
|
||
<li><b>deep-copy</b> semantics: copies of the container implies copies of the value.</li>
|
||
<li><b>deep-relational</b> semantics: comparisons between containers compare container size and if match, contained value</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 behavior
|
||
of trying to access the value of an uninitialized optional</li>
|
||
</blockquote>
|
||
|
||
<h3><u>The semantics:</u></h3>
|
||
<p>Objects of type <code>optional<T></code> are intended to be used in places where objects of type T would
|
||
but which might be uninitialized. Hence, <code>optional<T></code>'s purpose is to formalize the
|
||
additional possibly uninitialized state.<br>
|
||
From the perspective of this role, <code>optional<T></code> can have the same operational semantics of T
|
||
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
|
||
built-in type.</p>
|
||
|
||
<p>We can draw from the purpose of optional<T> the required basic semantics:</p>
|
||
|
||
<blockquote>
|
||
<p><b>Default Construction:</b> To introduce a formally uninitialized wrapped
|
||
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 new yet equivalent wrapped
|
||
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>Assignment (upon initialized):</b> To assign to the wrapped object the value
|
||
of another wrapped 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
|
||
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 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>
|
||
|
||
</blockquote>
|
||
|
||
<p>Additional operations are useful, such as converting constructors and
|
||
converting assignments, in-place construction and assignment, and safe value
|
||
access via a pointer to the wrapped object or null.</p>
|
||
<h3><u>The Interface:</u></h3>
|
||
<p>Since the purpose of optional is to allow us to use objects with a formal
|
||
uninitialized additional state, the interface could try to follow the interface
|
||
of the underlying T type as much as possible. In order to choose the proper
|
||
degree of adoption of the native T interface, the following must be noted: <br>
|
||
Even if all the operations supported by an instance of type T are defined for
|
||
the entire range of values for such a type, an optional<T> extends such a set of
|
||
values with a new value for which most (otherwise valid) operations are not
|
||
defined in terms of T.<br>
|
||
Furthermore, since optional<T> itself is merely a T wrapper (modeling a T
|
||
supertype), any attempt to define such operations upon uninitialized optionals
|
||
will be totally artificial w.r.t. T.<br>
|
||
This library chooses an interface which follows from T's interface only for
|
||
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 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>
|
||
<h3>Lexically-hinted Value Access in the presence of possibly untitialized
|
||
optional objects: The operators * and -></h3>
|
||
<p>A relevant feature of a pointer is that it can have a <b>null
|
||
pointer value</b>. This is a <i>special</i> value which is used to indicate that the
|
||
pointer is not referring to any object at all. In other words, null pointer
|
||
values convey the notion of inexistent objects.</P>
|
||
<P>This meaning of the null pointer value allowed pointers to became a <i>de facto</i> standard
|
||
for handling optional objects because all you have to do to refer to a value which you
|
||
don't really have is to use a null pointer value of the appropriate type.
|
||
Pointers have been used for decades—from the days of C APIs to modern C++ libraries—to
|
||
<i>refer</i> to optional (that is, possibly inexistent) objects; particularly
|
||
as optional arguments to a function, but also quite often as optional data members.</P>
|
||
<P>The possible presence of a null pointer value makes the operations that access the
|
||
pointee's value possibly undefined, therefore, expressions which use dereference
|
||
and access operators, such as: <code>( *p = 2 )</code> and <code>( p->foo())</code>,
|
||
implicitly convey the notion of optionality, and this information is tied to
|
||
the <i>syntax</i> of the expressions. That is, the presence of operators * and -> tell by
|
||
themselves—without any additional context—that the expression will be undefined unless
|
||
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 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
|
||
them. The problem resides in the shallow-copy of pointer semantics: if you need to
|
||
effectively move or copy the object, pointers alone are not enough. The problem
|
||
is that copies of pointers do not imply copies of pointees. For example, as
|
||
was discussed in the motivation, pointers alone cannot be used to return optional
|
||
objects from a function because the object must move outside from the function and
|
||
into the caller's context.<br>
|
||
A solution to the shallow-copy problem that is often used is to resort to dynamic
|
||
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 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 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 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<> 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;
|
||
but relational operators for pointers are shallow: they do not compare pointee values.<br>
|
||
As a result, you might be able to replace optional<T> by T* on some situations but
|
||
not always. Specifically, on generic code written for both, you cannot use relational
|
||
operators directly, and must use the template functions
|
||
<a href="../../utility/OptionalPointee.html#equal">equal_pointees()</a> and
|
||
<a href="../../utility/OptionalPointee.html#less">less_pointees()</a> instead.
|
||
<HR>
|
||
|
||
<H2><A NAME="synopsis">Synopsis</A></H2>
|
||
|
||
<PRE>namespace boost {
|
||
|
||
template<class T>
|
||
class optional
|
||
{
|
||
public :
|
||
|
||
<i><u>(If T is of reference type, the parameters and results by reference are by value)</u></i>
|
||
|
||
optional () ;
|
||
|
||
optional ( none_t ) ;
|
||
|
||
optional ( T const& v ) ;
|
||
|
||
optional ( optional const& rhs ) ;
|
||
|
||
template<class U> explicit optional ( optional<U> const& rhs ) ;
|
||
|
||
template<class InPlaceFactory> explicit optional ( InPlaceFactory const& f ) ;
|
||
|
||
template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ;
|
||
|
||
optional& operator = ( none_t ) ;
|
||
|
||
optional& operator = ( T const& v ) ;
|
||
|
||
optional& operator = ( optional const& rhs ) ;
|
||
|
||
template<class U> optional& operator = ( optional<U> const& rhs ) ;
|
||
|
||
template<class InPlaceFactory> optional& operator = ( InPlaceFactory const& f ) ;
|
||
|
||
template<class TypedInPlaceFactory> optional& operator = ( TypedInPlaceFactory const& f ) ;
|
||
|
||
T const& get() const ;
|
||
T& get() ;
|
||
|
||
T const* operator ->() const ;
|
||
T* operator ->() ;
|
||
|
||
T const& operator *() const ;
|
||
T& operator *() ;
|
||
|
||
T const* get_ptr() const ;
|
||
T* get_ptr() ;
|
||
|
||
operator <i>unspecified-bool-type</i>() const ;
|
||
|
||
bool operator!() const ;
|
||
|
||
<i><u>deprecated methods</u></i>
|
||
|
||
void reset() ; (deprecated)
|
||
void reset ( T const& ) ; (deprecated)
|
||
bool is_initialized() const ; (deprecated)
|
||
|
||
} ;
|
||
|
||
template<class T> inline bool operator == ( optional<T> const& x, optional<T> const& y ) ;
|
||
|
||
template<class T> inline bool operator != ( optional<T> const& x, optional<T> const& y ) ;
|
||
|
||
template<class T> inline bool operator < ( optional<T> const& x, optional<T> const& y ) ;
|
||
|
||
template<class T> inline bool operator > ( optional<T> const& x, optional<T> const& y ) ;
|
||
|
||
template<class T> inline bool operator <= ( optional<T> const& x, optional<T> const& y ) ;
|
||
|
||
template<class T> inline bool operator >= ( optional<T> const& x, optional<T> const& y ) ;
|
||
|
||
template<class T> inline T const& get ( optional<T> const& opt ) ;
|
||
|
||
template<class T> inline T& get ( optional<T> & opt ) ;
|
||
|
||
template<class T> inline T const* get ( optional<T> const* opt ) ;
|
||
|
||
template<class T> inline T* get ( optional<T>* opt ) ;
|
||
|
||
template<class T> inline T const* get_pointer ( optional<T> const& opt ) ;
|
||
|
||
template<class T> inline T* get_pointer ( optional<T> & opt ) ;
|
||
|
||
template<class T> inline void swap( optional<T>& x, optional<T>& y ) ;
|
||
|
||
} // namespace boost
|
||
</PRE>
|
||
|
||
<HR>
|
||
|
||
<h2><A NAME="semantics">Detailed Semantics</a></h2>
|
||
|
||
<p><b><u>NOTES: </u></b></p>
|
||
|
||
<p><b>Because T might be of reference type, in the sequel, those entries whose
|
||
semantic depends on T being of reference type or not will be distinguished using
|
||
the following convention:<br>
|
||
If the entry reads: optional<T (not a ref)>, the description corresponds only to
|
||
the case where T is not of reference type.<br>
|
||
If the entry reads: optional<T&>, the description corresponds only to the case
|
||
where T is of reference type. <br>
|
||
If the entry reads: optional<T>, the description is the same for both cases.</b></p>
|
||
|
||
<p><i>The following section contains various assert() which are used only to
|
||
show the postconditions as sample code. It is not implied that the type T must
|
||
support each particular expression but that if the expression is supported, the
|
||
implied condition holds.</i></p>
|
||
|
||
<hr>
|
||
|
||
<pre>optional<T>::optional();</pre>
|
||
<blockquote>
|
||
<p><b>Effect:</b> Default-Constructs an <b>optional</b>.</p>
|
||
<p><b>Postconditions:</b> <b>*this</b> is <u>uninitialized</u>.</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b> T's default constructor <u><i>is not</i></u> called.</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>optional<T> def ;
|
||
assert ( !def ) ;</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<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>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b></p>
|
||
<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::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>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<pre>optional<T <i>(not a ref)</i>>::optional( T const& v )</pre>
|
||
<blockquote>
|
||
<p><b>Effect:</b> Directly-Constructs an <b>optional</b>.</p>
|
||
<!-- TemplateName: general/sy_footer_inc.isml -->
|
||
<p><b>Postconditions:</b> <b>*this</b> is <u>initialized</u> and its value is a <i>copy</i> of 'v'.</p>
|
||
<p><b>Throws:</b> Whatever T::T( T const& ) throws.</p>
|
||
<p><b>Notes: </b> T::T( T const& ) is called.</p>
|
||
<p><b>Exception Safety:</b> Exceptions can only be thrown during T::T( T const& );
|
||
in that case, this constructor has no effect.
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>T v;
|
||
optional<T> opt(v);
|
||
assert ( *opt == v ) ;</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<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
|
||
instance of an internal type wrapping the reference 'ref'.</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>T v;
|
||
T& vref = v ;
|
||
optional<T&> opt(vref);
|
||
assert ( *opt == v ) ;
|
||
++ v ; // mutate referee
|
||
assert (*opt == v); </pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<pre>optional<T <i>(not a ref)</i>>::optional( optional const& rhs );</pre>
|
||
<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 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>rhs</b> is initialized, T::T(T const& ) is called.</p>
|
||
<p><b>Exception Safety:</b> Exceptions can only be thrown during T::T( T const& );
|
||
in that case, this constructor has no effect.
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>optional<T> uninit ;
|
||
assert (!uninit);
|
||
|
||
optional<T> uinit2 ( uninit ) ;
|
||
assert ( uninit2 == uninit );
|
||
|
||
optional<T> init( T(2) );
|
||
assert ( *init == T(2) ) ;
|
||
|
||
optional<T> init2 ( init ) ;
|
||
assert ( init2 == init ) ;
|
||
</pre>
|
||
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<pre>optional<T&>::optional( optional const& rhs );</pre>
|
||
<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 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, 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 ;
|
||
assert (!uninit);
|
||
|
||
optional<T&> uinit2 ( uninit ) ;
|
||
assert ( uninit2 == uninit );
|
||
|
||
T v = 2 ; T& ref = v ;
|
||
optional<T> init(ref);
|
||
assert ( *init == v ) ;
|
||
|
||
optional<T> init2 ( init ) ;
|
||
assert ( *init2 == v ) ;
|
||
|
||
v = 3 ;
|
||
|
||
assert ( *init == 3 ) ;
|
||
assert ( *init2 == 3 ) ;
|
||
|
||
|
||
</pre>
|
||
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<pre>template<U> explicit optional<T <i>(not a ref)</i>>::optional( optional<U> const& rhs );</pre>
|
||
<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 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> 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> Exceptions can only be thrown during T::T( U const& );
|
||
in that case, this constructor has no effect.
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
|
||
<pre>optional<double> x(123.4);
|
||
assert ( *x == 123.4 ) ;
|
||
|
||
optional<int> y(x) ;
|
||
assert( *y == 123 ) ;
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<pre>template<<i>InPlaceFactory</i>> explicit optional<T <i>(not a ref)</i>>::optional( <i>InPlaceFactory</i> const& f );</pre>
|
||
|
||
<pre>template<<i>TypedInPlaceFactory</i>> explicit optional<T <i>(not a ref)</i>>::optional( <i>TypedInPlaceFactory</i> const& f );</pre>
|
||
<blockquote>
|
||
<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>
|
||
<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
|
||
T constructor used by the factory;
|
||
in that case, this constructor has no effect.
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
|
||
<pre>class C { C ( char, double, std::string ) ; } ;
|
||
|
||
C v('A',123.4,"hello");
|
||
|
||
optional<C> x( in_place ('A', 123.4, "hello") ); // InPlaceFactory used
|
||
optional<C> y( in_place<C>('A', 123.4, "hello") ); // TypedInPlaceFactory used
|
||
|
||
assert ( *x == v ) ;
|
||
assert ( *y == v ) ;
|
||
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<pre>optional& optional<T <i>(not a ref)</i>>::operator= ( T const& rhs ) ;</pre>
|
||
<blockquote>
|
||
<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::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 ) ;</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>
|
||
|
||
<HR>
|
||
|
||
<pre>optional& optional<T <i>(not a ref)</i>>::operator= ( optional const& rhs ) ;</pre>
|
||
<blockquote>
|
||
<p><b>Effect:</b> Assigns another <b>optional</b> to 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 value of <b>rhs</b>; else <b>*this</b>
|
||
is uninitialized.
|
||
</p>
|
||
<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> def ;
|
||
|
||
opt = def ;
|
||
assert ( !def ) ;
|
||
// previous value (copy of 'v') destroyed from within 'opt'.
|
||
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<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>
|
||
<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 value of <b>rhs</b> <i>converted</i>
|
||
to type T; else <b>*this</b> is uninitialized.
|
||
</p>
|
||
<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;
|
||
optional<T> opt0(v);
|
||
optional<U> opt1;
|
||
|
||
opt1 = opt0 ;
|
||
assert ( *opt1 == static_cast<U>(v) ) ;
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
<pre>void optional<T <i>(not a ref)</i>>::reset( T const& v ) ;</pre>
|
||
<blockquote>
|
||
<p><b>Deprecated:</b> same as operator= ( T const& v) ;</p>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
<pre>void optional<T>::reset() ;</pre>
|
||
<blockquote>
|
||
<p><b>Deprecated: </b>Same as operator=( detail::none_t );</p>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
|
||
<pre>T const& optional<T <i>(not a ref)</i>>::operator*() const ;
|
||
T& optional<T<i> (not a ref)</i>>::operator*();</pre>
|
||
|
||
<pre>T const& optional<T <i>(not a ref)</i>>::get() const ;
|
||
T& optional<T <i>(not a ref)</i>>::get() ;
|
||
|
||
inline T const& get ( optional<T<i> (not a ref)</i>> const& ) ;
|
||
inline T& get ( optional<T <i>(not a ref)</i>> &) ;
|
||
</pre>
|
||
<blockquote>
|
||
<p><b>Requirements: *this</b> is initialized</p>
|
||
<p><b>Returns:</b> A reference to the contained value</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b> The requirement is asserted via BOOST_ASSERT().</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>T v ;
|
||
optional<T> opt ( v );
|
||
T const& u = *opt;
|
||
assert ( u == v ) ;
|
||
T w ;
|
||
*opt = w ;
|
||
assert ( *opt == w ) ;
|
||
</pre>
|
||
</blockquote>
|
||
<pre></pre>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
|
||
<pre>T const& optional<T&>::operator*() const ;
|
||
T & optional<T<i>&</i>>::operator*();</pre>
|
||
|
||
<pre>T const& optional<T&>::get() const ;
|
||
T& optional<T&>::get() ;
|
||
|
||
inline T const& get ( optional<T<i>&</i>> const& ) ;
|
||
inline T& get ( optional<T&> &) ;
|
||
</pre>
|
||
<blockquote>
|
||
<p><b>Requirements: *this</b> is initialized</p>
|
||
<p><b>Returns:</b> <u>The</u> reference contained.</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b> The requirement is asserted via BOOST_ASSERT().</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>T v ;
|
||
T& vref = v ;
|
||
optional<T&> opt ( vref );
|
||
T const& vref2 = *opt;
|
||
assert ( vref2 == v ) ;
|
||
++ v ;
|
||
assert ( *opt == v ) ;</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<pre>T const* optional<T <i>(not a ref)</i>>::get_ptr() const ;
|
||
T* optional<T <i>(not a ref)</i>>::get_ptr() ;
|
||
|
||
inline T const* get_pointer ( optional<T <i>(not a ref)</i>> const& ) ;
|
||
inline T* get_pointer ( optional<T <i>(not a ref)</i>> &) ;
|
||
</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> If <b>*this</b> is initialized, a pointer to the contained
|
||
value; else 0 (<i>null</i>).
|
||
</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b> The contained value is permanently stored within *this, so
|
||
you should not hold nor delete this pointer
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>T v;
|
||
optional<T> opt(v);
|
||
optional<T> const copt(v);
|
||
T* p = opt.get_ptr() ;
|
||
T const* cp = copt.get_ptr();
|
||
assert ( p == get_pointer(opt) );
|
||
assert ( cp == get_pointer(copt) ) ;
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
|
||
<HR>
|
||
|
||
|
||
<pre>T const* optional<T <i>(not a ref)</i>>::operator ->() const ;
|
||
T* optional<T <i>(not a ref)</i>>::operator ->() ;
|
||
</pre>
|
||
<blockquote>
|
||
<p><b>Requirements: *this</b> is initialized.</p>
|
||
<p><b>Returns:</b> A pointer to the contained value.</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b> The requirement is asserted via BOOST_ASSERT().</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>struct X { int mdata ; } ;
|
||
X x ;
|
||
optional<X> opt (x);
|
||
opt->mdata = 2 ;
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
|
||
<HR>
|
||
|
||
|
||
<pre>optional<T>::operator <i>unspecified-bool-type</i>() const ;</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> An unspecified value which if used on a boolean context is equivalent to (get() != 0)</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<blockquote>
|
||
<pre>optional<T> def ;
|
||
assert ( def == 0 );
|
||
optional<T> opt ( v ) ;
|
||
assert ( opt );
|
||
assert ( opt != 0 );
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
|
||
<pre> bool optional<T>::operator!() ;</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> If <b>*this</b> is uninitialized, <code>true</code>; else <code>false.</code></p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b> This operator is provided for those compilers which can't use
|
||
the <i>unspecified-bool-type</i> operator in certain boolean contexts.
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>optional<T> opt ;
|
||
assert ( !opt );
|
||
*opt = some_T ;
|
||
|
||
// Notice the "double-bang" idiom here.
|
||
assert ( !!opt ) ;
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
|
||
<HR>
|
||
|
||
|
||
<pre>bool optional<T>::is_initialized() const ;</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> <i>true</i> is the <b>optional</b> is initialized, <i>false</i>
|
||
otherwise.</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<blockquote>
|
||
<pre>optional<T> def ;
|
||
assert ( !def.is_initialized() );
|
||
optional<T> opt ( v ) ;
|
||
assert ( opt.is_initialized() );</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
|
||
<pre>bool operator == ( optional<T> const& x, optional<T> const& y );</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> If both <b>x</b> and <b>y</b> are initialied, <code>(*x == *y)</code>.
|
||
If only x or y is initialized, <code>false</code>. If both are uninitialized, <code>true</code>.
|
||
</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b> Pointers have shallow relational operators while <b>optional</b> 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 <a href="../../utility/OptionalPointee.html#equal">equal_pointees()</a> instead
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>T x(12);
|
||
T y(12);
|
||
T z(21);
|
||
optional<T> def0 ;
|
||
optional<T> def1 ;
|
||
optional<T> optX(x);
|
||
optional<T> optY(y);
|
||
optional<T> optZ(z);
|
||
|
||
// Identity always hold
|
||
assert ( def0 == def0 );
|
||
assert ( optX == optX );
|
||
|
||
// Both uninitialized compare equal
|
||
assert ( def0 == def1 );
|
||
|
||
// Only one initialized compare unequal.
|
||
assert ( def0 != optX );
|
||
|
||
// Both initialized compare as (*lhs == *rhs)
|
||
assert ( optX == optY ) ;
|
||
assert ( optX != optZ ) ;
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
|
||
<pre>bool operator < ( optional<T> const& x, optional<T> const& y );</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> If <b>y</b> is not initialized, <code>false</code>.
|
||
If <b>y</b> is initialized and <b>x</b> is not initialized, <code>true</code>.
|
||
If both <b>x</b> and <b>y</b> are initialized, <code>(*x < *y)</code>.
|
||
</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
<p><b>Notes:</b> Pointers have shallow relational operators while <b>optional</b> 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 <a href="../../utility/OptionalPointee.html#less">less_pointees()</a> instead
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>T x(12);
|
||
T y(34);
|
||
optional<T> def ;
|
||
optional<T> optX(x);
|
||
optional<T> optY(y);
|
||
|
||
// Identity always hold
|
||
assert ( !(def < def) );
|
||
assert ( optX == optX );
|
||
|
||
// Both uninitialized compare equal
|
||
assert ( def0 == def1 );
|
||
|
||
// Only one initialized compare unequal.
|
||
assert ( def0 != optX );
|
||
|
||
// Both initialized compare as (*lhs == *rhs)
|
||
assert ( optX == optY ) ;
|
||
assert ( optX != optZ ) ;
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
<pre>bool operator != ( optional<T> const& x, optional<T> const& y );
|
||
</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> !( x == y );</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
<pre>bool operator > ( optional<T> const& x, optional<T> const& y );
|
||
</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> ( y < x );</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
<pre>bool operator <= ( optional<T> const& x, optional<T> const& y );
|
||
</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> !( y<x );</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
<pre>bool operator >= ( optional<T> const& x, optional<T> const& y );
|
||
</pre>
|
||
<blockquote>
|
||
<p><b>Returns:</b> !( x<y );</p>
|
||
<p><b>Throws:</b> Nothing.</p>
|
||
</blockquote>
|
||
|
||
<HR>
|
||
|
||
<pre>void swap ( optional<T>& x, optional<T>& y );</pre>
|
||
|
||
<blockquote>
|
||
<p><b>Effect:</b> If both <b>x</b> and <b>y</b> are initialized, calls <code>swap(*x,*y)</code>
|
||
using std::swap.<br>
|
||
If only one is initialized, say x, calls: <code>y.reset(*x); x.reset();</code><br>
|
||
If none is initialized, does nothing.
|
||
</p>
|
||
<p><b>Postconditions:</b> The states of x and y interchanged.</p>
|
||
<p><b>Throws:</b> If both are initialized, whatever swap(T&,T&) throws.
|
||
If only one is initialized, whatever T::T ( T const& ) throws.
|
||
</p>
|
||
<p><b>Notes:</b> If both are initialized, swap(T&,T&) is used <i>unqualified</i>
|
||
but with std::swap introduced in scope.<br>
|
||
If only one is initialized, T::~T() and T::T( T const& ) is called.
|
||
</p>
|
||
<p><b>Exception Safety:</b> If both are initialized, this operation has the exception
|
||
safety guarantees of swap(T&,T&).<br>
|
||
If only one is initialized, it has the same <b>basic</b> guarantee as optional<T>::reset( T const& ).
|
||
</p>
|
||
<p><b>Example:</b></p>
|
||
<blockquote>
|
||
<pre>T x(12);
|
||
T y(21);
|
||
optional<T> def0 ;
|
||
optional<T> def1 ;
|
||
optional<T> optX(x);
|
||
optional<T> optY(y);
|
||
|
||
boost::swap(def0,def1); // no-op
|
||
|
||
boost::swap(def0,optX);
|
||
assert ( *def0 == x );
|
||
assert ( !optX );
|
||
|
||
boost::swap(def0,optX); // Get back to original values
|
||
|
||
boost::swap(optX,optY);
|
||
assert ( *optX == y );
|
||
assert ( *optY == x );
|
||
|
||
</pre>
|
||
</blockquote>
|
||
</blockquote>
|
||
<HR>
|
||
|
||
<H2><A NAME="examples">Examples</A></H2>
|
||
|
||
<h3>Optional return values</h3>
|
||
<PRE>optional<char> get_async_input()
|
||
{
|
||
if ( !queue.empty() )
|
||
return optional<char>(queue.top());
|
||
else return optional<char>(); // uninitialized
|
||
}
|
||
|
||
void receive_async_message()
|
||
{
|
||
optional<char> rcv ;
|
||
// The safe boolean conversion from 'rcv' is used here.
|
||
while ( (rcv = get_async_input()) && !timeout() )
|
||
output(*rcv);
|
||
}
|
||
</pre>
|
||
|
||
<h3>Optional local variables</h3>
|
||
<pre>optional<string> name ;
|
||
if ( database.open() )
|
||
{
|
||
name.reset ( database.lookup(employer_name) ) ;
|
||
}
|
||
else
|
||
{
|
||
if ( can_ask_user )
|
||
name.reset ( user.ask(employer_name) ) ;
|
||
}
|
||
|
||
if ( name )
|
||
print(*name);
|
||
else print("employer's name not found!");
|
||
</pre>
|
||
|
||
<h3>Optional data members</h3>
|
||
<pre>class figure
|
||
{
|
||
public:
|
||
|
||
figure()
|
||
{
|
||
// data member 'm_clipping_rect' is uninitialized at this point.
|
||
}
|
||
|
||
void clip_in_rect ( rect const& rect )
|
||
{
|
||
....
|
||
m_clipping_rect.reset ( rect ) ; // initialized here.
|
||
}
|
||
|
||
void draw ( canvas& cvs )
|
||
{
|
||
if ( m_clipping_rect )
|
||
do_clipping(*m_clipping_rect);
|
||
|
||
cvs.drawXXX(..);
|
||
}
|
||
|
||
// this can return NULL.
|
||
rect const* get_clipping_rect() { return get_pointer(m_clipping_rect); }
|
||
|
||
private :
|
||
|
||
optional<rect> m_clipping_rect ;
|
||
|
||
};
|
||
</pre>
|
||
<h3>Bypassing expensive unnecessary default construction</h3>
|
||
<pre>class ExpensiveCtor { ... } ;
|
||
class Fred
|
||
{
|
||
Fred() : mLargeVector(10000) {}
|
||
|
||
std::vector< optional<ExpensiveCtor> > mLargeVector ;
|
||
} ;
|
||
</pre>
|
||
|
||
<HR>
|
||
|
||
<H2><A NAME="ref">Optional references</A></H2>
|
||
<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
|
||
some operations are not available in this case:</p>
|
||
|
||
<ul>
|
||
<li>Converting constructors</li>
|
||
<li>Converting assignment</li>
|
||
<li>InPlace construction</li>
|
||
<li>InPlace assignment</li>
|
||
<li>Value-access via pointer</li>
|
||
</ul>
|
||
<p>Also, even though optional<T&> treats it wrapped pseudo-object much as a real
|
||
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 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>
|
||
<p>
|
||
One of the typical problems with wrappers and containers is that their
|
||
interfaces usually provide an operation to initialize or assign the contained
|
||
object as a copy of some other object. This not only requires the underlying
|
||
type to be <a href="../../utility/CopyConstructible.html">Copy Constructible</a>, but also requires the existence of a fully
|
||
constructed object, often temporary, just to follow the copy from:</p>
|
||
<pre>struct X
|
||
{
|
||
X ( int, std:::string ) ;
|
||
} ;</pre>
|
||
<pre>class W
|
||
{
|
||
X wrapped_ ;
|
||
|
||
public:
|
||
|
||
W ( X const& x ) : wrapped_(x) {}
|
||
} ;</pre>
|
||
<pre>void foo()
|
||
{
|
||
// Temporary object created.
|
||
W ( X(123,"hello") ) ;
|
||
}
|
||
</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 scheme, the user only needs to supply the arguments to the constructor
|
||
to use in the wrapped object construction.</p>
|
||
<pre>class W
|
||
{
|
||
X wrapped_ ;
|
||
|
||
public:
|
||
|
||
W ( X const& x ) : wrapped_(x) {}
|
||
W ( int a0, std::string a1) : wrapped_(a0,a1) {}
|
||
} ;</pre>
|
||
<pre>void foo()
|
||
{
|
||
// Wrapped object constructed in-place
|
||
// No temporary created.
|
||
W (123,"hello") ;
|
||
}
|
||
</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 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 family looks like:</p>
|
||
<pre>template<class T,class A0, class A1>
|
||
class TypedInPlaceFactory2
|
||
{
|
||
A0 m_a0 ; A1 m_a1 ;
|
||
|
||
public:
|
||
|
||
TypedInPlaceFactory2( A0 const& a0, A1 const& a1 ) : m_a0(a0), m_a1(a1) {}
|
||
|
||
void construct ( void* p ) { new (p) T(m_a0,m_a1) ; }
|
||
} ;
|
||
</pre>
|
||
<p>A wrapper class aware of this can use it as:</p>
|
||
<pre>class W
|
||
{
|
||
X wrapped_ ;
|
||
|
||
public:
|
||
|
||
W ( X const& x ) : wrapped_(x) {}
|
||
W ( TypedInPlaceFactory2 const& fac ) { fac.construct(&wrapped_) ; }
|
||
} ;</pre>
|
||
<pre>void foo()
|
||
{
|
||
// Wrapped object constructed in-place via a TypedInPlaceFactory.
|
||
// No temporary created.
|
||
W ( TypedInPlaceFactory2<X,int,std::string&rt;(123,"hello")) ;
|
||
}
|
||
</pre>
|
||
<p>The factories are divided in two groups:<ul>
|
||
<li><u>TypedInPlaceFactories</u>: those which take the target type as a primary template parameter.</li>
|
||
<li><u>InPlaceFactories</u>: those with a template <code>construct(void*)</code> member function taking the target type.</li>
|
||
</ul>
|
||
<p>Within each group, all the family members differ only in the number of parameters allowed.</p>
|
||
<p></p>
|
||
<p>This library provides an overloaded set of helper template functions to construct these factories
|
||
without requiring unnecessary template parameters:</p>
|
||
<pre>template<class A0,...,class AN>
|
||
InPlaceFactory<i>N </i><A0,...,AN> <b>in_place</b> ( A0 const& a0, ..., AN const& aN) ;
|
||
|
||
template<class T,class A0,...,class AN>
|
||
TypedInPlaceFactory<i>N </i><T,A0,...,AN> <b>in_place</b> ( T const& a0, A0 const& a0, ..., AN const& aN) ;</pre>
|
||
|
||
<p>In-place factories can be used generically by the wrapper and user as follows:</p>
|
||
<pre>class W
|
||
{
|
||
X wrapped_ ;
|
||
|
||
public:
|
||
|
||
W ( X const& x ) : wrapped_(x) {}
|
||
|
||
template<class InPlaceFactory></class>
|
||
W ( InPlaceFactory const& fac ) { fac.template <X>construct(&wrapped_) ; }
|
||
|
||
} ;</pre>
|
||
<pre>void foo()
|
||
{
|
||
// Wrapped object constructed in-place via a InPlaceFactory.
|
||
// No temporary created.
|
||
W ( in_place(123,"hello") ) ;
|
||
}
|
||
</pre>
|
||
<p>The factories are implemented in the headers:
|
||
<a href="../../../boost/utility/in_place_factory.hpp">in_place_factory.hpp</a> and
|
||
<a href="../../../boost/utility/typed_in_place_factory.hpp">typed_in_place_factory.hpp</a>
|
||
</p>
|
||
|
||
<HR>
|
||
|
||
<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 <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>
|
||
<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>
|
||
<pre>void foo ( bool v ) ;
|
||
void bar()
|
||
{
|
||
optional<bool> v = try();
|
||
|
||
// The following intended to pass the <b>value</b> of 'v' to foo():
|
||
foo(v);
|
||
// But instead, the <i>initialization state</i> is passed
|
||
// due to a typo: it should have been foo(<b>*</b>v).
|
||
}
|
||
</pre>
|
||
<p>The only implicit conversion is to bool, and it is <i>safe</i> in the sense that typical
|
||
integral promotions don't apply (i.e. if foo() takes an 'int' instead, it won't compile). <HR>
|
||
|
||
<H2><A NAME="exsafety">Exception Safety Guarantees</A></H2>
|
||
<H3><u>Assignment and Reset:</u></H3>
|
||
<p>Because of the current implementation (see <A HREF="#impl">Implementation Notes</A>), all
|
||
of the assignment methods:</p>
|
||
<ul>
|
||
<li> <code>optional<T>::operator= ( optional<T> const& ) </code>
|
||
</li>
|
||
<li> <code>optional<T>::operator= ( T const& ) </code></li>
|
||
<li> <code>template<class U> optional<T>::operator= ( optional<U> const& ) </code>
|
||
</li>
|
||
<li> <code>template<class InPlaceFactory> optional<T>::operator= (
|
||
InPlaceFactory const& ) </code></li>
|
||
<li> <code>template<class TypedInPlaceFactory> optional<T>::operator= (
|
||
TypedInPlaceFactory const& ) </code></li>
|
||
<li> <code>optional<T>:::reset ( T const&)</code></li>
|
||
</ul>
|
||
<p>Can only <i>guarantee</i> the <u>basic exception safety</u>: The lvalue optional is left <u>uninitialized</u>
|
||
if an exception is thrown (any previous value is <i>first</i> destroyed using T::~T())</p>
|
||
<p>On the other hand, the <i>uninitializing</i> methods:</p>
|
||
<ul>
|
||
<li><code>optional<T>::operator= ( detail::none_t ) </code></li>
|
||
<li><code>optional<T>::reset()</code></li>
|
||
</ul>
|
||
<p>Provide the no-throw guarantee (assuming a no-throw T::~T())</p>
|
||
<p>However, since <code>optional<></code> itself doesn't throw any exceptions,
|
||
the only source for exceptions here are T's constructor, so if you know the exception guarantees
|
||
for T::T ( T const& ), you know that optional's assignment and reset has the same guarantees.</p>
|
||
<pre>//
|
||
// Case 1: Exception thrown during assignment.
|
||
//
|
||
T v0(123);
|
||
optional<T> opt0(v0);
|
||
try
|
||
{
|
||
T v1(456);
|
||
optional<T> opt1(v1);
|
||
opt0 = opt1 ;
|
||
|
||
// If no exception was thrown, assignment succeeded.
|
||
assert( *opt0 == v1 ) ;
|
||
}
|
||
catch(...)
|
||
{
|
||
// If any exception was thrown, 'opt0' is reset to uninitialized.
|
||
assert( !opt0 ) ;
|
||
}
|
||
|
||
//
|
||
// Case 2: Exception thrown during reset(v)
|
||
//
|
||
T v0(123);
|
||
optional<T> opt(v0);
|
||
try
|
||
{
|
||
T v1(456);
|
||
opt.reset ( v1 ) ;
|
||
|
||
// If no exception was thrown, reset succeeded.
|
||
assert( *opt == v1 ) ;
|
||
}
|
||
catch(...)
|
||
{
|
||
// If any exception was thrown, 'opt' is reset to uninitialized.
|
||
assert( !opt ) ;
|
||
}
|
||
</pre>
|
||
<H3><u>Swap:</u></H3>
|
||
<p><code>void swap( optional<T>&, optional<T>& )</code> has the same exception guarantee as <code>swap(T&,T&)</code> when both optionals are initialized.<br>
|
||
If only one of the optionals is initialized, it gives the same <i>basic</i> exception guarantee as <code>optional<T>::reset( T const& )</code> (since <code>optional<T>::reset()</code> doesn't throw).<br>
|
||
If none of the optionals is initialized, it has no-throw guarantee since it is a no-op. </p>
|
||
|
||
<HR>
|
||
|
||
<H2><A NAME="requirements">Type requirements</A></H2>
|
||
<p>In general, T must be <a href="../../utility/CopyConstructible.html">Copy Constructible</a> and have a no-throw destructor. The copy-constructible requirement is not needed
|
||
if InPlaceFactories are used.<br>
|
||
T <u>is not</u> required to be <a href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default Constructible</a> </p>
|
||
|
||
<HR>
|
||
|
||
<H2><A NAME="impl">Implementation Notes</A></H2>
|
||
<p>optional<T> is currently implemented
|
||
using a custom aligned storage facility built from <code>alignment_of</code> and <code>type_with_alignment</code> (both from Type Traits).
|
||
It uses a separate boolean flag to indicate the initialization state.<br>
|
||
Placement new with T's copy constructor and T's destructor
|
||
are explicitly used to initialize,copy and destroy optional values.<br>
|
||
As a result, T's default constructor is effectively by-passed, but the exception
|
||
guarantees are basic.<br>
|
||
It is planned to replace the current implementation with another with
|
||
stronger exception safety, such as a future boost::variant<T,nil_t>. </p>
|
||
|
||
<HR>
|
||
|
||
<H2><A NAME="porta">Dependencies and Portability</A></H2>
|
||
|
||
<p>The implementation uses <code>type_traits/alignment_of.hpp</code> and <code>type_traits/type_with_alignment.hpp</code></p>
|
||
|
||
<HR>
|
||
|
||
<H2><A NAME="credits">Acknowledgments</A></H2>
|
||
<p>Pre-formal review:</p>
|
||
<blockquote>
|
||
<p>Peter Dimov suggested the name 'optional', and was the first to point out the
|
||
need for aligned storage<br>
|
||
Douglas Gregor developed 'type_with_alignment', and later Eric Friedman coded
|
||
'aligned_storage', which are the core of the optional class implementation.<br>
|
||
Andrei Alexandrescu and Brian Parker also worked with aligned storage techniques
|
||
and their work influenced the current implementation.<br>
|
||
Gennadiy Rozental made extensive and important comments which shaped the design.<br>
|
||
Vesa Karvonen and Douglas Gregor made quite useful comparisons between optional,
|
||
variant and any; and made other relevant comments. Douglas Gregor and Peter
|
||
Dimov commented on comparisons and evaluation in boolean contexts.<br>
|
||
Eric Friedman helped understand the issues involved with aligned storage, move/copy
|
||
operations and exception safety.<br>
|
||
Many others have participated with useful comments: Aleksey Gurotov, Kevlin
|
||
Henney, David Abrahams, and others I can't recall. </p>
|
||
</blockquote>
|
||
<p>Post-formal review:</p>
|
||
<blockquote>
|
||
<p>William Kempf carefully considered the originally proposed interface and
|
||
suggested the new interface which is currently used. He also started and fueled
|
||
the discussion about the analogy optional<>/smart pointer and about
|
||
relational operators.<br>
|
||
Peter Dimov, Joel de Guzman, David Abrahams, Tanton Gibbs and Ian Hanson focused
|
||
on the relational semantics of optional (originally undefined); concluding
|
||
with the fact that the pointer-like interface doesn't make it a pointer so
|
||
it shall have deep relational operators.<br>
|
||
Augustus Saunders also explored the different relational semantics between
|
||
optional<> and a pointer and developed the OptionalPointee concept as
|
||
an aid against potential conflicts on generic code.<br>
|
||
Joel de Guzman noticed that optional<> can be seen as an API on top
|
||
of variant<T,nil_t>.<br>
|
||
Dave Gomboc explained the meaning and usage of the Haskell analog to optional<>:
|
||
the Maybe type constructor (analogy originally pointed out by David Sankel).<br>
|
||
Other comments were posted by Vincent Finn, Anthony Williams, Ed Brey, Rob
|
||
Stewart, and others.<br>
|
||
Joel de Guzman made the case for the support of references and helped with
|
||
the proper semantics.<br>
|
||
Mat Marcus shown the virtues of a value-oriented interface, influencing the
|
||
current design, and contributed the idea of "none".</p>
|
||
</blockquote>
|
||
<HR>
|
||
|
||
<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">
|
||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||
<P>Developed by <A HREF="mailto:fernando_cacciola@hotmail.com">Fernando Cacciola</A>,
|
||
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> |