Compare commits

..

60 Commits

Author SHA1 Message Date
2ae7b5a53b This commit was manufactured by cvs2svn to create branch
'array_wrapper'.

[SVN r31998]
2005-12-12 15:22:03 +00:00
f89c517fa8 Large patch from Ulrich Eckhardt to fix support for EVC++ 4.
[SVN r30670]
2005-08-25 16:27:28 +00:00
b831e5f88d Typos fixed
[SVN r29952]
2005-07-08 23:22:29 +00:00
88d002a7be Doc fixes
[SVN r29158]
2005-05-23 14:04:03 +00:00
dda39772ad Fix doubled EOLs.
[SVN r28438]
2005-04-23 16:35:57 +00:00
ed504fae7b Converted to Unix format
[SVN r28432]
2005-04-23 02:59:05 +00:00
9a0013d668 Optional's Assignment fixed
[SVN r28412]
2005-04-22 13:28:34 +00:00
361d945b5c fixed couple of html-typos
[SVN r25985]
2004-10-30 20:34:18 +00:00
d61baf2a94 bad links fixed
added myself to people


[SVN r25610]
2004-10-07 16:01:24 +00:00
1412c04b24 c++boost.gif -> boost.png replacement
[SVN r25573]
2004-10-05 15:45:52 +00:00
24c5f92413 In-place factories moved from /detail to /utility
New value_initalized tests added


[SVN r25436]
2004-09-27 12:28:21 +00:00
07a80c1b9b In-place factories moved from /detail to /utility
New value_initalized tests added


[SVN r25313]
2004-09-21 14:54:32 +00:00
7717a785de Fix some typos
[SVN r23844]
2004-07-20 14:42:19 +00:00
3db413cc30 Pseudo-destructor fixed (fix adjusted for BCB6)
[SVN r23632]
2004-07-16 14:42:25 +00:00
46fafdb7c9 Fix outdated reference to boost/detail/none.hpp, to current boost/none.hpp.
[SVN r23439]
2004-07-11 16:40:21 +00:00
9aa4943b7a Pseudo-destructor fixed
[SVN r23393]
2004-07-07 15:13:25 +00:00
7cacecb6f9 Pseudo-destructor fixed
[SVN r23392]
2004-07-07 15:04:52 +00:00
0109fabef4 Fixed test for bcc5.6.4 weak overload resolution
[SVN r22138]
2004-02-02 15:40:12 +00:00
dce592e3b2 Added acknowldegment to Mat Marcus
[SVN r22074]
2004-01-30 13:17:22 +00:00
05045f5be7 Fixed overload resolution problem with operator= in bcc5.6.4
[SVN r21999]
2004-01-27 13:46:50 +00:00
8d85b4c47b Fixed documentation for operator<
[SVN r21738]
2004-01-14 20:22:56 +00:00
3ca0557a7c Sync with V1 Jamfile.
[SVN r21563]
2004-01-09 11:28:42 +00:00
50d7c315d5 Fix link to variant library
[SVN r21184]
2003-12-08 14:18:54 +00:00
24416ae806 Updated to reflect additions
[SVN r21131]
2003-12-04 01:45:19 +00:00
44f140f961 Removed obsolete test
[SVN r20994]
2003-11-28 15:40:20 +00:00
943df2a9aa No longer needed
[SVN r20993]
2003-11-28 15:38:57 +00:00
c18e5d9464 Fixed bcc5.5.1
[SVN r20991]
2003-11-28 15:33:51 +00:00
7bd27ccace Some headers were moved from "utility" to "detail"
[SVN r20990]
2003-11-28 15:33:07 +00:00
855d343cd1 Renamed
[SVN r20985]
2003-11-28 15:08:12 +00:00
1fc75ce00e Renamed (because of the 31 max chars limit)
[SVN r20984]
2003-11-28 15:04:23 +00:00
d469aff043 Moved from "utility" to "detail" until a Fast Track Review formalizes it.
[SVN r20983]
2003-11-28 14:36:21 +00:00
2a85470f49 Simplify and clean up
[SVN r20870]
2003-11-19 22:22:02 +00:00
f8fe66e289 Still mre bcc5.5.1 compat fixes
[SVN r20727]
2003-11-07 14:57:30 +00:00
6c70e16379 More bcc5.5.1 compatibility fixes.
[SVN r20671]
2003-11-05 00:03:23 +00:00
51975011a9 More compiler compatibility fixes. New License
[SVN r20608]
2003-11-03 03:02:06 +00:00
38c609e126 New License
[SVN r20607]
2003-11-03 02:59:08 +00:00
d0cf7efaf0 BCB551 and VC6 compatibility fixes
[SVN r20565]
2003-10-30 14:45:50 +00:00
9adda8450b VC6 compatibility fixes
[SVN r20564]
2003-10-30 14:45:13 +00:00
65464ceffd Reference semantics change rolledback (deffered to after 1.31.0)
[SVN r20557]
2003-10-30 00:39:34 +00:00
3b7d49e4aa *** empty log message ***
[SVN r20549]
2003-10-29 15:47:01 +00:00
e8a91e1ce3 Compiler compatibility fixes
[SVN r20548]
2003-10-29 15:46:28 +00:00
3468bfb07f Compiler compatibility fixes; Reference assignment changed (if the lhs is initialized, the assignment goes to the referenced object, thus the reference is not rebound)
[SVN r20546]
2003-10-29 15:45:12 +00:00
faa3c1962a Tests updated to reflect 1.15 changes
[SVN r20512]
2003-10-28 00:11:49 +00:00
b64b2cb0be *** empty log message ***
[SVN r20511]
2003-10-28 00:09:18 +00:00
6b70058cf0 VC fixes for in-place constructor overloads, reference types are now assignable, none_t support added, compare_pointees.hpp factored out
[SVN r20510]
2003-10-28 00:03:17 +00:00
18b8685e5d Fix typo
[SVN r20216]
2003-09-30 06:32:06 +00:00
920820c1d0 Add V2 Jamfile
[SVN r20212]
2003-09-29 16:40:02 +00:00
52896b097e Typed in place construction added
[SVN r20070]
2003-09-15 20:28:10 +00:00
161540a0eb Fixed access bug in type helpers
[SVN r20029]
2003-09-11 21:56:07 +00:00
3568ed7d0e Removed
[SVN r19999]
2003-09-10 15:56:14 +00:00
cd5ccd166b New tests added
[SVN r19998]
2003-09-10 15:53:25 +00:00
a1d8949039 *** empty log message ***
[SVN r19997]
2003-09-10 15:47:00 +00:00
d888dd2454 Additional tests
[SVN r19996]
2003-09-10 15:41:37 +00:00
a2f8c2fd41 Added functionality
[SVN r19994]
2003-09-10 15:39:30 +00:00
0ba0ff8ce3 Use the import rule
[SVN r19968]
2003-09-08 17:38:49 +00:00
5a595a9a92 repair the previous GCC fix, now works on gcc 2.95, 3.0, and 3.3
[SVN r19686]
2003-08-18 18:51:55 +00:00
042d3e08b8 fix compilation guard for "using std::swap"
[SVN r19009]
2003-07-09 23:13:40 +00:00
7d8ab81d48 typo fixed and em-dash used instead of a single hypen for parenthetical phrases.
[SVN r17923]
2003-03-14 20:40:08 +00:00
0267424bfe Added BOOST_DEDUCED_TYPENAME to fix compilation failures.
[SVN r17912]
2003-03-14 12:56:01 +00:00
1e7b26738e Fixed alignment bug (::type missing)
[SVN r17890]
2003-03-13 12:54:53 +00:00
13 changed files with 28 additions and 2466 deletions

View File

@ -1,982 +0,0 @@
<!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-Type" CONTENT="text/html; charset=iso-8859-1">
<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="../../../c++boost.gif" WIDTH="276" HEIGHT="86">Header &lt;<A
HREF="../../../boost/optional.hpp">boost/optional.hpp</A>&gt; </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="#bool">A note about optional&lt;bool&gt;</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 asssert 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&lt;point,bool&gt;.
</P>
<P>Returning a std::pair&lt;T,bool&gt;, 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&lt;char,bool&gt; get_async_input();
std::pair&lt;point,bool&gt; polygon::get_any_point_effectively_inside();</pre>
<p>These functions use a consistent interface for dealing with possibly inexistent
results:</p>
<pre>std::pair&lt;point,bool&gt; 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>The model</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 inital value</i> (c.f. 8.5.9).<br>
<code>optional&lt;T&gt;</code> intends to formalize the notion of initialization/no-initialization
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,
when a variable is declared as optional&lt;T&gt; 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>
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. And 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.
On modern languages, this can be modeled with a <b>discriminated
union</b> of T and something else such as a trivial POD or enum.
Discriminated unions are often called <i>variants</i>.
A variant has a <i>current type</i>, which in our case is either T or something else. In C++,
such a variant would be typically implemented as a template class of the form: <code>variant&lt;T,nil_t&gt;</code>
</P>
<P>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.</p>
<p>A discriminated union, which can be seen as a <b>container</b> which has an object of either
type T or something else, has <i>exactly</i> the semantics required for a wrapper of optional values:</p>
<li><b>deep-copy</b> semantics: copies of the variant implies copies of the contained 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 behaviour
of trying to access the value of an uninitialized optional</li>
<P>Because of the way a discriminated union is used for this purpose, it only matters
whether its current type is T or not. We can put a layer on top of the variant hidding the other type
transforming a container of fixed size 1 into a variable size container which either has
a T or has nothing. Thus, the variant&lt;T,nil_t&gt; can be seen as if it were a variable-size
fixed-capacity stack-based container with the following optional-oriented interface:</P>
<pre>// Uninitialized (internally, current type is nil_t)
optional&lt;T&gt;::optional();
// Initialized with 'v' (internally, current type is T)
optional&lt;T&gt;::optional( T const&amp; v ) ;
// Back to uninitialized (current type is set to nil_t)
void optional&lt;T&gt;::reset();
// Assigns 'v' whether previously initialized or not (current type is set to T)
void optional&lt;T&gt;::reset( T const&amp; v ) ;
// Returns 'true' if the optional is initialized, 'false' otherwise.
bool optional&lt;T&gt;::initialized() ;
// If the optional is initialized (current type is T), returns a reference to its value.
// Otherwise (current type is nil_t), the result is undefined.
T const&amp; optional&lt;T&gt;::ref() const ;
T&amp; optional&lt;T&gt;::ref() ;
// If both are initialized, calls swap(T&amp;,T&amp;);
// If only one is initialized, calls reset(T const&amp;) and reset().
// If both are uninitalized, do nothing.
void swap ( optional&lt;T&gt;&amp; lhs, optional&lt;T&gt;&amp; rhs ) ;
// If both are initialized, compare values.
// If only one is initialized, they are not equal.
// If both are uninitalized, they are equal.
bool operator == ( optional&lt;T&gt; const&amp; lhs, optional&lt;T&gt; const&amp; rhs ) ;
bool operator != ( optional&lt;T&gt; const&amp; lhs, optional&lt;T&gt; const&amp; rhs ) ;
</pre>
<h3>Pointers and optional objects</h3>
<P>In C++, unlike many other languages, objects can be referenced <i>indirectly</i>
by means of a <b>pointer</b> (or a reference). Pointers have several nice features,
two of which are relevant to this development.</p>
<p>One is that a pointer has its own <i>pointer value</i>, which in effect
references the object being pointed to: the <b>pointee</b>. Consequently,
copies of pointers do not involve copies of pointees. This effect results in <i>aliasing</i>:
different pointers can refer to the same object.
The particular semantic that a copy of a pointer does not involve
a copy of the pointee is called <b>shallow-copy</b>, which is oppossed to <b>deep-copy</b> were
a copy of a wrapper involves a copy of the wrapped object (as with optional&lt;&gt;)<br>
Since this is the semantic followed by pointers (and references), shallow-copy
(and therefore aliasing) is implied in <b>pointer semantics</b>.</p>
<p>The other relevant feature of a pointer is that a pointer 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 defacto 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&mdash;from the days of C APIs to modern C++ libraries&mdash;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-&gt;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 -&gt; tell by
themselves&mdash;without any additional context&mdash;that the expression will be undefined unless
the implied pointee actually exist.<br>
Furthermore, the existence of the pointee can be tested by a comparison against
the null pointer value or via a conversion to bool, which allows expressions of
the form: if ( p != 0 ), or if ( p ) to be used to test for the existence of the pointee.</P>
<p>Such a defacto 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
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&lt;X&gt;
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.
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
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. <br>
Therefore, the final solution which is presented in this library is to shape the
previously discussed optional&mdash;which is a value-based container&mdash;as a model
of the OptionalPointee concept.
</p>
<h3>Optional&lt;T&gt; as a model of OptionalPointee</h3>
<P>The optional&lt;&gt; template class presented with this library is a variation of the
sketch shown before (as a layer on top of a variant). It features <b>deep-copy</b> and
<b>deep relational operators</b>, but also models the OptionalPointee concept.
Instead of the member function 'initialized()' it has a safe conversion to bool,
and instead of the 'ref()' member function, it has operators*() and ->().<br>
However, it is particularly important that optional<> objects are not mistaken by pointers,
they are not. <u><b>optional&lt;&gt; does not model a pointer</b></u>.
For instance, optional&lt;&gt; has not shallow-copy so does not alias: two different optionals
never refer to the <i>same</i> value (but may have <i>equivalent</i> values).<br>
The difference between an optional&lt;T&gt; and a pointer must be kept in mind, particularly
because the semantics of relational operators are different: since optional&lt;T&gt;
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&lt;T&gt; 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 function
<a href="../../utility/OptionalPointee.html#equal">equal_pointees()</a> instead.
<HR>
<H2><A NAME="synopsis">Synopsis</A></H2>
<PRE>namespace boost {
template&lt;class T>
class optional
{
public :
optional () ;
explicit optional ( T const&amp; v ) ;
optional ( optional const&amp; rhs ) ;
template&lt;class U&gt; explicit optional ( optional&lt;U&gt; const&amp; rhs ) ;
optional&amp; operator = ( optional const&amp; rhs ) ;
template&lt;class U&gt; optional&amp; operator = ( optional&lt;U&gt; const&amp rhs ) ;
T const* get() const ;
T* get() ;
T const* operator -&gt;() const ;
T* operator -&gt;() ;
T const&amp; operator *() const ;
T&amp; operator *() ;
void reset();
void reset ( T const&amp; ) ;
operator <i>unspecified-bool-type</i>() const ;
bool operator!() const ;
} ;
template&lt;class T&gt; inline bool operator == ( optional&lt;T&gt; const& x, optional&lt;T&gt; const& y ) ;
template&lt;class T&gt; inline bool operator != ( optional&lt;T&gt; const& x, optional&lt;T&gt; const& y ) ;
template&lt;class T&gt; inline T* get_pointer ( optional&lt;T&gt; const& opt ) ;
template&lt;class T&gt; inline void swap( optional&lt;T&gt;& x, optional&lt;T&gt;&amp; y ) ;
} // namespace boost
</PRE>
<HR>
<h2><A NAME="semantics">Semantics</a></h2>
<p><i>Note: 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&lt;T&gt;::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&lt;T&gt; def ;
assert ( !def ) ;</pre>
</blockquote>
</blockquote>
<HR>
<pre>explicit optional&lt;T&gt;::optional( T const&amp; v )</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 a <i>copy</i> of 'v'.</p>
<p><b>Throws:</b> Whatever T::T( T const&amp; ) throws.</p>
<p><b>Notes:</b> T::T( T const&amp; ) is called.</p>
<p><b>Exception Safety:</b> Exceptions can only be thrown during T::T( T const&amp; );
in that case, this constructor has no effect.
</p>
<p><b>Example:</b></p>
<blockquote>
<pre>
T v;
optional&lt;T&gt; opt(v);
assert ( *opt == v ) ;
</pre>
</blockquote>
</blockquote>
<HR>
<pre>optional&lt;T&gt;::optional( optional const&amp; 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> T::T( T const& ) is called if <b>rhs</b> is initialized.</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&lt;T&gt; uninit ;
assert (!uninit);
optional&lt;T&gt; uinit2 ( uninit ) ;
assert ( uninit2 == uninit );
optional&lt;T&gt; init( T(2) );
assert ( *init == T(2) ) ;
optional&lt;T&gt; init2 ( init ) ;
assert ( init2 == init ) ;
</pre>
</blockquote>
</blockquote>
<HR>
<pre>explicit template&lt;U&gt; optional&lt;T&gt;::optional( optional&lt;U&gt; const&amp; 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&lt;double&gt; x(123.4);
assert ( *x == 123.4 ) ;
optional&lt;int&gt; y(x) ;
assert( *y == 123 ) ;
</pre>
</blockquote>
</blockquote>
<HR>
<pre>optional&amp; optional&lt;T&gt;::operator= ( optional const&amp; 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::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>
<p><b>Example:</b></p>
<blockquote>
<pre>
T v;
optional&lt;T&gt; opt(v);
optional&lt;T&gt; uninit ;
opt = uninit ;
assert ( !opt ) ;
// previous value (copy of 'v') destroyed from within 'opt'.
</pre>
</blockquote>
</blockquote>
<HR>
<pre>template&ltU&gt; optional&amp; optional&lt;T&gt;::operator= ( optional&lt;U&gt; const&amp; 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::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>
<p><b>Example:</b></p>
<blockquote>
<pre>
T v;
optional&lt;T&gt; opt0(v);
optional&lt;U&gt; opt1;
opt1 = opt0 ;
assert ( *opt1 == static_cast&lt;U&gt;(v) ) ;
</pre>
</blockquote>
</blockquote>
<HR>
<pre>void optional&lt;T&gt;::reset( T const&amp v ) ;</pre>
<blockquote>
<p><b>Effect:</b> Resets the current value.</p>
<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> If <b>*this</b> was initialized, it is first reset to uninitialized
using T::~T(), then T::T( T const& ) 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>Example:</b></p>
<blockquote>
<pre>optional&lt;T&gt; opt ( some_T ) ;
assert( *opt == some_T );
opt.reset ( some_other_T ) ;
assert( *opt == some_other_T );
</pre>
</blockquote>
</blockquote>
<HR>
<pre>void optional&lt;T&gt;::reset() ;</pre>
<blockquote>
<p><b>Effect:</b> Destroys the current value.</p>
<p><b>Postconditions: *this</b> is uninitialized.</p>
<p><b>Throws:</b> Nothing.</p>
<p><b>Notes:</b> T::~T() is called.</p>
<p><b>Example:</b></p>
<blockquote>
<pre>optional&lt;T&gt; opt ( some_T ) ;
assert( *opt == some_T );
opt.reset();
assert( !opt );
</pre>
</blockquote>
</blockquote>
<HR>
<pre>
T const* optional&lt;T&gt;::get() const ;
T* optional&lt;T&gt;::get() ;
inline T const* get_pointer ( optional&lt;T&gt; const&amp; ) ;
inline T* get_pointer ( optional&lt;T&gt;&amp;) ;
</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&lt;T&gt; opt(v);
optional&lt;T&gt; const copt(v);
T* p = opt.get() ;
T const* cp = copt.get();
assert ( p == get_pointer(opt) );
assert ( cp == get_pointer(copt) ) ;
</pre>
</blockquote>
</blockquote>
<HR>
<pre>
T const* optional&lt;T&gt;::operator -&gt;() const ;
T* optional&lt;T&gt;::operator -&gt;() ;
</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&lt;X&gt; opt (x);
opt-&gt;mdata = 2 ;
</pre>
</blockquote>
</blockquote>
<HR>
<pre>T const&amp; optional&lt;T&gt;::operator*() const ;
T&amp; optional&lt;T&gt;::operator*();</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&lt;T&gt; opt ( v );
T const&amp; u = *opt;
assert ( u == v ) ;
T w ;
*opt = w ;
assert ( *opt == w ) ;
</pre>
</blockquote>
</blockquote>
<HR>
<pre>optional&lt;T&gt;::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&lt;T&gt; def ;
assert ( def == 0 );
optional&lt;T&gt; opt ( v ) ;
assert ( opt );
assert ( opt != 0 );
</pre>
</blockquote>
</blockquote>
<HR>
<pre> bool optional&lt;T&gt;::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&lt;T&gt; opt ;
assert ( !opt );
*opt = some_T ;
// Notice the &quot;double-bang&quot; idiom here.
assert ( !!opt ) ;
</pre>
</blockquote>
</blockquote>
<HR>
<pre>bool operator == ( optional&lt;T&gt; const&amp x, optional&lt;T&gt const&amp 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&lt;T&gt; 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&lt;T&gt; def0 ;
optional&lt;T&gt; def1 ;
optional&lt;T&gt; optX(x);
optional&lt;T&gt; optY(y);
optional&lt;T&gt; 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&lt;T&gt; const&amp x, optional&lt;T&gt const&amp y );
</pre>
<blockquote>
<p><b>Returns:</b> !( x == y );</p>
<p><b>Throws:</b> Nothing.</p>
</blockquote>
<HR>
<pre>void swap ( optional&lt;T&gt;&amp x, optional&lt;T&gt&amp 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&amp;,T&amp;) throws.
If only one is initialized, whatever T::T ( T const&amp; ) throws.
</p>
<p><b>Notes:</b> If both are initialized, swap(T&amp;,T&amp;) 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&lt;T&gt;::reset( T const& ).
</p>
<p><b>Example:</b></p>
<blockquote>
<pre>
T x(12);
T y(21);
optional&lt;T&gt; def0 ;
optional&lt;T&gt; def1 ;
optional&lt;T&gt; optX(x);
optional&lt;T&gt; 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&lt;char&gt; get_async_input()
{
if ( !queue.empty() )
return optional&lt;char&gt;(queue.top());
else return optional&lt;char&gt;(); // uninitialized
}
void recieve_async_message()
{
optional&lt;char&gt; rcv ;
// The safe boolean conversion from 'rcv' is used here.
while ( (rcv = get_async_input()) &amp;&amp; !timeout() )
output(*rcv);
}
</pre>
<h3>Optional local variables</h3>
<pre>optional&lt;string&gt; 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(&quot;employer's name not found!&quot;);
</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&amp; 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&lt;rect&gt; m_clipping_rect ;
};
</pre>
<h3>Bypassing expensive unnecesary default construction</h3>
<pre>class ExpensiveCtor { ... } ;
class Fred
{
Fred() : mLargeVector(10000) {}
std::vector< optional&lt;ExpensiveCtor&gt; > mLargeVector ;
} ;
</pre>
<HR>
<H2><A NAME="bool">A note about optional&lt;bool&gt;</A></H2>
<p><code>optional&lt;bool&gt;</code> should be used with special caution and consideration.</p>
<p>First, it is functionally similar to a tristate boolean (false,maybe,true) &mdash;such as
<u>boost::tribool</u> (not yet formally in boost)&mdash;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&lt;bool&gt;.<br>
It should be carefully considered if an optional bool instead of a tribool is really needed</p>
<p>Second, optional&lt;&gt; provides an implicit conversion to bool. This conversion
refers to the initialization state and not to the contained value.<br>
Using optional&lt;bool&gt; can lead to subtle errors due to the implicit bool conversion:</p>
<pre>
void foo ( bool v ) ;
void bar()
{
optional&lt;bool&gt; 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>),
<code> optional&lt;T&gt;::operator=( optional&lt;T&gt; const&amp; )
and optional&lt;T&gt;::reset( T const&amp; )</code>
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><code>optional&lt;T&gt;::reset()</code> provides the no-throw guarantee (assuming a no-throw T::~T())</p>
<p>However, since <code>optional&lt&gt</code> itself doesn't throw any exceptions,
the only source for exceptions here is T's copy constructor, so if you know the exception guarantees
for T::T ( T const&amp; ), you know that optional's assignment and reset has the same guarantees.</p>
<pre>//
// Case 1: Exception thrown during assignment.
//
T v0(123);
optional&ltT&gt opt0(v0);
try
{
T v1(456);
optional&ltT&gt 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&ltT&gt 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&lt;T&gt;&amp;, optional&lt;T&gt;&amp; )</code>
has the same exception guarantee as <code>swap(T&amp;,T&amp;)</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&lt;T&gt;::reset( T const&amp; )</code>
(since <code>optional&lt;T&gt;::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>T must be <a href="../../utility/CopyConstructible.html">Copy Constructible</a>
and have a no-throw destructor.<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&lt;T&gt; 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>
<p>It has been tested on bcc5.5.1, vc6.0 and gcc2.95.2</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&lt;&gt;/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&lt;&gt; and a pointer and developed the
OptionalPointee concept as an aid against potential conflicts on generic code.<br>
Joel de Guzman noticed that optional&lt;&gt; can be seen as an
API on top of variant&lt;T,nil_t&gt;.<br>
Dave Gomboc explained the meaning and usage of the Haskell analog to optional&lt;&gt;:
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.
</p>
</blockquote>
<HR>
<P>Revised January 20, 2003</P>
<P>&copy; Copyright boost.org 2003. Permission to copy, use, modify, sell and
distribute this document is granted provided this copyright notice appears in
all copies. This document is provided &quot;as is&quot; without express or
implied warranty, and with no claim as to its suitability for any purpose.</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 discussion list at
<A
HREF="http://www.yahoogroups.com/list/boost">www.yahoogroups.com/list/boost</A>.
</P>
</BODY>
</HTML>

View File

@ -0,0 +1,28 @@
// 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_DETAIL_NONE_T_17SEP2003_HPP
#define BOOST_DETAIL_NONE_T_17SEP2003_HPP
namespace boost {
namespace detail {
struct none_helper{};
typedef int none_helper::*none_t ;
} // namespace detail
} // namespace boost
#endif

View File

@ -1,323 +0,0 @@
// (C) 2003, Fernando Luis Cacciola Carballal.
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// See http://www.boost.org/lib/optional for documentation.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#ifndef BOOST_OPTIONAL_FLC_19NOV2002_HPP
#define BOOST_OPTIONAL_FLC_19NOV2002_HPP
#include<new>
#include<algorithm>
#include "boost/config.hpp"
#include "boost/assert.hpp"
#include "boost/type_traits/alignment_of.hpp"
#include "boost/type_traits/type_with_alignment.hpp"
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
// VC6.0 has the following bug:
// When a templated assignment operator exist, an implicit conversion
// constructing an optional<T> is used when assigment of the form:
// optional<T> opt ; opt = T(...);
// is compiled.
// However, optional's ctor is _explicit_ and the assignemt shouldn't compile.
// Therefore, for VC6.0 templated assignment is disabled.
//
#define BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT
#endif
#if BOOST_WORKAROUND(BOOST_MSVC, == 1300)
// VC7.0 has the following bug:
// When both a non-template and a template copy-ctor exist
// and the templated version is made 'explicit', the explicit is also
// given to the non-templated version, making the class non-implicitely-copyable.
//
#define BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR
#endif
namespace boost
{
namespace optional_detail
{
template <class T>
class aligned_storage
{
// Borland ICEs if unnamed unions are used for this!
union dummy_u
{
char data[ sizeof(T) ];
BOOST_DEDUCED_TYPENAME type_with_alignment<
::boost::alignment_of<T>::value >::type aligner_;
} dummy_ ;
public:
void const* address() const { return &dummy_.data[0]; }
void * address() { return &dummy_.data[0]; }
} ;
}
template<class T>
class optional
{
typedef optional<T> this_type ;
typedef optional_detail::aligned_storage<T> storage_type ;
typedef void (this_type::*unspecified_bool_type)();
public :
typedef T value_type ;
// Creates an optional<T> uninitialized.
// No-throw
optional ()
:
m_initialized(false) {}
// Creates an optional<T> initialized with 'val'.
// Can throw if T::T(T const&) does
explicit optional ( T const& val )
:
m_initialized(false)
{
construct(val);
}
#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR
// NOTE: MSVC needs templated versions first
// Creates a deep copy of another convertible optional<U>
// Requires a valid conversion from U to T.
// Can throw if T::T(U const&) does
template<class U>
explicit optional ( optional<U> const& rhs )
:
m_initialized(false)
{
if ( rhs )
construct(*rhs);
}
#endif
// Creates a deep copy of another optional<T>
// Can throw if T::T(T const&) does
optional ( optional const& rhs )
:
m_initialized(false)
{
if ( rhs )
construct(*rhs);
}
// No-throw (assuming T::~T() doesn't)
~optional() { destroy() ; }
#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.
// Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED
template<class U>
optional& operator= ( optional<U> const& rhs )
{
destroy(); // no-throw
if ( rhs )
{
// An exception can be thrown here.
// It it happens, THIS will be left uninitialized.
construct(*rhs);
}
return *this ;
}
#endif
// Assigns from another optional<T> (deep-copies the rhs value)
// Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED
optional& operator= ( optional const& rhs )
{
destroy(); // no-throw
if ( rhs )
{
// An exception can be thrown here.
// It it happens, THIS will be left uninitialized.
construct(*rhs);
}
return *this ;
}
// Destroys the current value, if any, leaving this UNINITIALIZED
// No-throw (assuming T::~T() doesn't)
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 ( T const& val )
{
destroy();
construct(val);
}
// Returns a pointer to the value if this is initialized, otherwise,
// returns NULL.
// No-throw
T const* get() const { return m_initialized ? static_cast<T const*>(m_storage.address()) : 0 ; }
T* get() { return m_initialized ? static_cast<T*> (m_storage.address()) : 0 ; }
// Returns a pointer to the value if this is initialized, otherwise,
// the behaviour is UNDEFINED
// No-throw
T const* operator->() const { BOOST_ASSERT(m_initialized) ; return static_cast<T const*>(m_storage.address()) ; }
T* operator->() { BOOST_ASSERT(m_initialized) ; return static_cast<T*> (m_storage.address()) ; }
// Returns a reference to the value if this is initialized, otherwise,
// the behaviour is UNDEFINED
// No-throw
T const& operator *() const { BOOST_ASSERT(m_initialized) ; return *static_cast<T const*>(m_storage.address()) ; }
T& operator *() { BOOST_ASSERT(m_initialized) ; return *static_cast<T*> (m_storage.address()) ; }
// implicit conversion to "bool"
// No-throw
operator unspecified_bool_type() const { return m_initialized ? &this_type::destroy : 0 ; }
// This is provided for those compilers which don't like the conversion to bool
// on some contexts.
bool operator!() const { return !m_initialized ; }
private :
void construct ( T const& val )
{
new (m_storage.address()) T(val) ;
m_initialized = true ;
}
void destroy()
{
if ( m_initialized )
{
get()->~T() ;
m_initialized = false ;
}
}
bool m_initialized ;
storage_type m_storage ;
} ;
// Returns a pointer to the value if this is initialized, otherwise, returns NULL.
// No-throw
template<class T>
inline
T const* get_pointer ( optional<T> const& opt )
{
return opt.get() ;
}
template<class T>
inline
T* get_pointer ( optional<T>& opt )
{
return opt.get() ;
}
// template<class OP> bool equal_pointees(OP const& x, OP const& y);
//
// Being OP a model of OptionalPointee (either a pointer or an optional):
//
// If both x and y have valid pointees, returns the result of (*x == *y)
// If only one has a valid pointee, returns false.
// If none have valid pointees, returns true.
// No-throw
template<class OptionalPointee>
inline
bool equal_pointees ( OptionalPointee const& x, OptionalPointee const& y )
{
return (!x) != (!y) ? false : ( !x ? true : (*x) == (*y) ) ;
}
// optional's operator == and != have deep-semantics (compare values).
// WARNING: This is UNLIKE pointers. Use equal_pointees() in generic code instead.
template<class T>
inline
bool operator == ( optional<T> const& x, optional<T> const& y )
{ return equal_pointees(x,y); }
template<class T>
inline
bool operator != ( optional<T> const& x, optional<T> const& y )
{ return !( x == y ) ; }
//
// The following swap implementation follows the GCC workaround as found in
// "boost/detail/compressed_pair.hpp"
//
namespace optional_detail {
// GCC < 3.2 gets the using declaration at namespace scope (FLC, DWA)
#if BOOST_WORKAROUND(__GNUC__, < 3) \
|| BOOST_WORKAROUND(__GNUC__, == 3) && __GNUC_MINOR__ <= 2
using std::swap;
#define BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE
#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 uninitialized, do nothing (no-throw)
template<class T>
inline
void optional_swap ( optional<T>& x, optional<T>& y )
{
if ( !x && !!y )
{
x.reset(*y); // Basic guarantee.
y.reset();
}
else if ( !!x && !y )
{
y.reset(*x); // Basic guarantee.
x.reset();
}
else if ( !!x && !!y )
{
// GCC > 3.2 and all other compilers have the using declaration at function scope (FLC)
#ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE
// allow for Koenig lookup
using std::swap ;
#endif
swap(*x,*y);
}
}
#undef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE
} // namespace optional_detail
template<class T> inline void swap ( optional<T>& x, optional<T>& y )
{
optional_detail::optional_swap(x,y);
}
} // namespace boost
#endif

View File

@ -1,9 +0,0 @@
<html>
<head>
<meta http-equiv="refresh" content="0; URL=doc/optional.html">
</head>
<body>
Automatic redirection failed, please go to
<a href="doc/optional.html">doc/optional.html</a>.
</body>
</html>

View File

@ -1 +0,0 @@
bin

View File

@ -1,37 +0,0 @@
# Boost.Optional Library test Jamfile
#
# Copyright (C) 2003, Fernando Luis Cacciola Carballal.
#
# This material is provided "as is", with absolutely no warranty expressed
# or implied. Any use is at your own risk.
#
# Permission to use or copy this software for any purpose is hereby granted
# without fee, provided the above notices are retained on all copies.
# Permission to modify the code and to distribute modified code is granted,
# provided the above notices are retained, and a notice that the code was
# modified is included with the above copyright notice.
#
subproject libs/optional/test ;
# bring in rules for testing
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
include testing.jam ;
# Make tests run by default.
DEPENDS all : test ;
{
# look in BOOST_ROOT for sources first, just in this Jamfile
local SEARCH_SOURCE = $(BOOST_ROOT) $(SEARCH_SOURCE) ;
test-suite optional :
[ run libs/optional/test/optional_test.cpp ]
[ compile-fail libs/optional/test/optional_test_fail1.cpp ]
[ compile-fail libs/optional/test/optional_test_fail2.cpp ]
[ compile-fail libs/optional/test/optional_test_fail3.cpp ]
[ compile-fail libs/optional/test/optional_test_fail4.cpp ]
[ compile-fail libs/optional/test/optional_test_fail5a.cpp ]
[ compile-fail libs/optional/test/optional_test_fail5b.cpp ]
;
}

View File

@ -1,938 +0,0 @@
// (C) 2003, Fernando Luis Cacciola Carballal.
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#include<iostream>
#include<stdexcept>
#include<string>
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
# include <boost/get_pointer.hpp>
#endif
#define BOOST_ENABLE_ASSERT_HANDLER
#include "boost/optional.hpp"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "boost/test/minimal.hpp"
#ifdef ENABLE_TRACE
#define TRACE(msg) std::cout << msg << std::endl ;
#else
#define TRACE(msg)
#endif
namespace boost {
void assertion_failed (char const * expr, char const * func, char const * file, long )
{
using std::string ;
string msg = string("Boost assertion failure for \"")
+ string(expr)
+ string("\" at file \"")
+ string(file)
+ string("\" function \"")
+ string(func)
+ string("\"") ;
TRACE(msg);
throw std::logic_error(msg);
}
}
using boost::optional ;
template<class T> inline void unused_variable ( T const& ) {}
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
using boost::swap ;
using boost::get_pointer ;
#endif
// MSVC6.0 does not support comparisons of optional against a literal null pointer value (0)
// via the safe_bool operator.
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1300) ) // 1300 == VC++ 7.1
#define BOOST_OPTIONAL_NO_NULL_COMPARE
#endif
#define ARG(T) (static_cast< T const* >(0))
//
// Helper class used to verify the lifetime managment of the values held by optional
//
class X
{
public :
X ( int av ) : v(av)
{
++ count ;
TRACE ( "X::X(" << av << "). this=" << this ) ;
}
X ( X const& rhs ) : v(rhs.v)
{
pending_copy = false ;
TRACE ( "X::X( X const& rhs). this=" << this << " rhs.v=" << rhs.v ) ;
if ( throw_on_copy )
{
TRACE ( "throwing exception in X's copy ctor" ) ;
throw 0 ;
}
++ count ;
}
~X()
{
pending_dtor = false ;
-- count ;
TRACE ( "X::~X(). v=" << v << " this=" << this );
}
X& operator= ( X const& rhs )
{
v = rhs.v ;
TRACE ( "X::operator =( X const& rhs). this=" << this << " rhs.v=" << rhs.v ) ;
return *this ;
}
friend bool operator == ( X const& a, X const& b )
{ return a.v == b.v ; }
friend bool operator != ( X const& a, X const& b )
{ return a.v != b.v ; }
friend bool operator < ( X const& a, X const& b )
{ return a.v < b.v ; }
int V() const { return v ; }
int& V() { return v ; }
static int count ;
static bool pending_copy ;
static bool pending_dtor ;
static bool throw_on_copy ;
private :
int v ;
private :
X() ;
} ;
int X::count = 0 ;
bool X::pending_copy = false ;
bool X::pending_dtor = false ;
bool X::throw_on_copy = 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 (...) {}
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 ; }
template<class T>
inline void check_uninitialized_const ( optional<T> const& opt )
{
#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE
BOOST_CHECK( opt == 0 ) ;
#endif
BOOST_CHECK( !opt ) ;
BOOST_CHECK( !get_pointer(opt) ) ;
BOOST_CHECK( !opt.get() ) ;
}
template<class T>
inline void check_uninitialized ( optional<T>& opt )
{
#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE
BOOST_CHECK( opt == 0 ) ;
#endif
BOOST_CHECK( !opt ) ;
BOOST_CHECK( !get_pointer(opt) ) ;
BOOST_CHECK( !opt.get() ) ;
check_uninitialized_const(opt);
}
template<class T>
inline void check_initialized_const ( optional<T> const& opt )
{
BOOST_CHECK( opt ) ;
#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE
BOOST_CHECK( opt != 0 ) ;
#endif
BOOST_CHECK ( !!opt ) ;
BOOST_CHECK ( get_pointer(opt) ) ;
BOOST_CHECK ( opt.get() ) ;
}
template<class T>
inline void check_initialized ( optional<T>& opt )
{
BOOST_CHECK( opt ) ;
#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE
BOOST_CHECK( opt != 0 ) ;
#endif
BOOST_CHECK ( !!opt ) ;
BOOST_CHECK ( get_pointer(opt) ) ;
BOOST_CHECK ( opt.get() ) ;
check_initialized_const(opt);
}
template<class T>
inline void check_value_const ( optional<T> const& opt, T const& v, T const& z )
{
BOOST_CHECK( *opt == v ) ;
BOOST_CHECK( *opt != z ) ;
BOOST_CHECK( (*(opt.operator->()) == v) ) ;
BOOST_CHECK( *get_pointer(opt) == v ) ;
BOOST_CHECK( *opt.get() == v ) ;
}
template<class T>
inline void check_value ( optional<T>& opt, T const& v, T const& z )
{
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1200) // 1200 == VC++ 6.0
// For some reason, VC6.0 is creating a temporary while evaluating (*opt == v),
// so we need to turn throw on copy off first.
reset_throw_on_copy( ARG(T) ) ;
#endif
BOOST_CHECK( *opt == v ) ;
BOOST_CHECK( *opt != z ) ;
BOOST_CHECK( (*(opt.operator->()) == v) ) ;
BOOST_CHECK( *get_pointer(opt) == v ) ;
BOOST_CHECK( *opt.get() == v ) ;
check_value_const(opt,v,z);
}
//
// Basic test.
// Check ordinary functionality:
// Initialization, assignment, comparison and value-accessing.
//
template<class T>
void test_basics( T const* )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
T z(0);
T a(1);
// Default construction.
// 'def' state is Uninitialized.
// T::T() is not called (and it is not even defined)
optional<T> def ;
check_uninitialized(def);
// Direct initialization.
// 'oa' state is Initialized with 'a'
// T::T( T const& x ) is used.
set_pending_copy( ARG(T) ) ;
optional<T> oa ( a ) ;
check_is_not_pending_copy( ARG(T) );
check_initialized(oa);
check_value(oa,a,z);
T b(2);
optional<T> ob ;
// Value-Assignment upon Uninitialized optional.
// T::T ( T const& x ) is used.
set_pending_copy( ARG(T) ) ;
ob.reset(a) ;
check_is_not_pending_copy( ARG(T) ) ;
check_initialized(ob);
check_value(ob,a,z);
// Value-Assignment upon Initialized optional.
// This uses T::operator= ( T const& x ) directly
// on the reference returned by operator*()
set_pending_dtor( ARG(T) ) ;
set_pending_copy( ARG(T) ) ;
*ob = b ;
check_is_pending_dtor( ARG(T) ) ;
check_is_pending_copy( ARG(T) ) ;
check_initialized(ob);
check_value(ob,b,z);
// Assignment initialization.
// T::T ( T const& x ) is used to copy new value.
set_pending_copy( ARG(T) ) ;
optional<T> const oa2 ( oa ) ;
check_is_not_pending_copy( ARG(T) ) ;
check_initialized_const(oa2);
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) ) ;
oa = ob ;
check_is_not_pending_dtor( ARG(T) ) ;
check_is_not_pending_copy( ARG(T) ) ;
check_initialized(oa);
check_value(oa,b,z);
// Uninitializing Assignment upon Initialized Optional
// T::~T() is used to destroy previous value in oa.
set_pending_dtor( ARG(T) ) ;
set_pending_copy( ARG(T) ) ;
oa = def ;
check_is_not_pending_dtor( ARG(T) ) ;
check_is_pending_copy ( ARG(T) ) ;
check_uninitialized(oa);
// Uninitializing Assignment upon Uninitialized Optional
// (Dtor is not called this time)
set_pending_dtor( ARG(T) ) ;
set_pending_copy( ARG(T) ) ;
oa = def ;
check_is_pending_dtor( ARG(T) ) ;
check_is_pending_copy( ARG(T) ) ;
check_uninitialized(oa);
// Deinitialization of Initialized Optional
// T::~T() is used to destroy previous value in ob.
set_pending_dtor( ARG(T) ) ;
ob.reset();
check_is_not_pending_dtor( ARG(T) ) ;
check_uninitialized(ob);
// Deinitialization of Uninitialized Optional
// (Dtor is not called this time)
set_pending_dtor( ARG(T) ) ;
ob.reset();
check_is_pending_dtor( ARG(T) ) ;
check_uninitialized(ob);
}
//
// Test Direct Value Manipulation
//
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) ;
optional<T> opt0(x);
BOOST_CHECK( c_opt0->V() == x.V() ) ;
BOOST_CHECK( opt0->V() == x.V() ) ;
BOOST_CHECK( (*c_opt0).V() == x.V() ) ;
BOOST_CHECK( (* opt0).V() == x.V() ) ;
T y(4);
*opt0 = y ;
BOOST_CHECK( (*opt0).V() == y.V() ) ;
BOOST_CHECK( x < (*opt0) ) ;
}
//
// Test Uninitialized access assert
//
template<class T>
void test_uninitialized_access( T const* )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
optional<T> def ;
bool passed = false ;
try
{
// This should throw because 'def' is uninitialized
T const& n = *def ;
unused_variable(n);
passed = true ;
}
catch (...) {}
BOOST_CHECK(!passed);
passed = false ;
try
{
T v(5) ;
unused_variable(v);
// This should throw because 'def' is uninitialized
*def = v ;
passed = true ;
}
catch (...) {}
BOOST_CHECK(!passed);
passed = false ;
try
{
// This should throw because 'def' is uninitialized
T v = *(def.operator->()) ;
unused_variable(v);
passed = true ;
}
catch (...) {}
BOOST_CHECK(!passed);
}
#if BOOST_WORKAROUND( BOOST_INTEL_CXX_VERSION, <= 700) // Intel C++ 7.0
void prevent_buggy_optimization( bool v ) {}
#endif
//
// Test Direct Initialization of optional for a T with throwing copy-ctor.
//
template<class T>
void test_throwing_direct_init( T const* )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
T a(6);
int count = get_instance_count( ARG(T) ) ;
set_throw_on_copy( ARG(T) ) ;
bool passed = false ;
try
{
// This should:
// Attempt to copy construct 'a' and throw.
// 'opt' won't be constructed.
set_pending_copy( ARG(T) ) ;
#if BOOST_WORKAROUND( BOOST_INTEL_CXX_VERSION, <= 700) // Intel C++ 7.0
// Intel C++ 7.0 specific:
// For some reason, when "check_is_not_pending_copy",
// after the exception block is reached,
// X::pending_copy==true even though X's copy ctor set it to false.
// I guessed there is some sort of optimization bug,
// and it seems to be the since the following additional line just
// solves the problem (!?)
prevent_buggy_optimization(X::pending_copy);
#endif
optional<T> opt(a) ;
passed = true ;
}
catch ( ... ){}
BOOST_CHECK(!passed);
check_is_not_pending_copy( ARG(T) );
check_instance_count(count, ARG(T) );
}
//
// Test Value Assignment to an Uninitialized optional for a T with a throwing copy-ctor
//
template<class T>
void test_throwing_val_assign_on_uninitialized( T const* )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
T a(7);
int count = get_instance_count( ARG(T) ) ;
set_throw_on_copy( ARG(T) ) ;
optional<T> opt ;
bool passed = false ;
try
{
// This should:
// Attempt to copy construct 'a' and throw.
// opt should be left uninitialized.
set_pending_copy( ARG(T) ) ;
opt.reset( a );
passed = true ;
}
catch ( ... ) {}
BOOST_CHECK(!passed);
check_is_not_pending_copy( ARG(T) );
check_instance_count(count, ARG(T) );
check_uninitialized(opt);
}
//
// Test Value Reset on an Initialized optional for a T with a throwing copy-ctor
//
template<class T>
void test_throwing_val_assign_on_initialized( T const* )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
T z(0);
T a(8);
T b(9);
int count = get_instance_count( ARG(T) ) ;
reset_throw_on_copy( ARG(T) ) ;
optional<T> opt ( b ) ;
++ count ;
check_instance_count(count, ARG(T) );
check_value(opt,b,z);
set_throw_on_copy( 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) ) ;
opt.reset ( a ) ;
passed = true ;
}
catch ( ... ) {}
BOOST_CHECK(!passed);
-- count ;
check_is_not_pending_dtor( ARG(T) );
check_is_not_pending_copy( ARG(T) );
check_instance_count(count, ARG(T) );
check_uninitialized(opt);
}
//
// Test Copy Initialization from an Initialized optional for a T with a throwing copy-ctor
//
template<class T>
void test_throwing_copy_initialization( T const* )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
T z(0);
T a(10);
reset_throw_on_copy( ARG(T) ) ;
optional<T> opt (a);
int count = get_instance_count( ARG(T) ) ;
set_throw_on_copy( ARG(T) ) ;
bool passed = false ;
try
{
// This should:
// Attempt to copy construct 'opt' and throw.
// opt1 won't be constructed.
set_pending_copy( ARG(T) ) ;
optional<T> opt1 = opt ;
passed = true ;
}
catch ( ... ) {}
BOOST_CHECK(!passed);
check_is_not_pending_copy( ARG(T) );
check_instance_count(count, ARG(T) );
// Nothing should have happened to the source optional.
check_initialized(opt);
check_value(opt,a,z);
}
//
// Test Assignment to an Uninitialized optional from an Initialized optional
// for a T with a throwing copy-ctor
//
template<class T>
void test_throwing_assign_to_uninitialized( T const* )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
T z(0);
T a(11);
reset_throw_on_copy( ARG(T) ) ;
optional<T> opt0 ;
optional<T> opt1(a) ;
int count = get_instance_count( ARG(T) ) ;
set_throw_on_copy( ARG(T) ) ;
bool passed = false ;
try
{
// This should:
// Attempt to copy construct 'opt1.value()' into opt0 and throw.
// opt0 should be left uninitialized.
set_pending_copy( ARG(T) ) ;
opt0 = opt1 ;
passed = true ;
}
catch ( ... ) {}
BOOST_CHECK(!passed);
check_is_not_pending_copy( ARG(T) );
check_instance_count(count, ARG(T) );
check_uninitialized(opt0);
}
//
// Test Assignment to an Initialized optional from an Initialized optional
// for a T with a throwing copy-ctor
//
template<class T>
void test_throwing_assign_to_initialized( T const* )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
T z(0);
T a(12);
T b(13);
reset_throw_on_copy( ARG(T) ) ;
optional<T> opt0(a) ;
optional<T> opt1(b) ;
int count = get_instance_count( ARG(T) ) ;
set_throw_on_copy( ARG(T) ) ;
bool passed = false ;
try
{
// This should:
// Attempt to copy construct 'opt1.value()' into opt0 and throw.
// opt0 should be left uninitialized (even though it was initialized)
set_pending_dtor( ARG(T) ) ;
set_pending_copy( ARG(T) ) ;
opt0 = opt1 ;
passed = true ;
}
catch ( ... ) {}
BOOST_CHECK(!passed);
-- count ;
check_is_not_pending_dtor( ARG(T) );
check_is_not_pending_copy( ARG(T) );
check_instance_count(count, ARG(T) );
check_uninitialized(opt0);
}
//
// Test swap in a no-throwing case
//
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) ;
optional<T> opt1(b) ;
int count = get_instance_count( ARG(T) ) ;
using boost::swap ;
swap(def0,def1);
check_uninitialized(def0);
check_uninitialized(def1);
swap(def0,opt0);
check_uninitialized(opt0);
check_initialized(def0);
check_value(def0,a,z);
// restore def0 and opt0
swap(def0,opt0);
swap(opt0,opt1);
check_instance_count(count, ARG(T) );
check_initialized(opt0);
check_initialized(opt1);
check_value(opt0,b,z);
check_value(opt1,a,z);
}
//
// Test swap in a throwing case
//
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) ) ;
optional<T> opt0(a) ;
optional<T> opt1(b) ;
set_throw_on_copy( ARG(T) ) ;
//
// Case 1: Both Initialized.
//
bool passed = false ;
try
{
// This should attempt to swap optionals and fail at swap(X&,X&).
swap(opt0,opt1);
passed = true ;
}
catch ( ... ) {}
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 ) ) ) ) ) ;
//
// Case 2: Only one Initialized.
//
reset_throw_on_copy( ARG(T) ) ;
opt0.reset();
opt1.reset(a);
set_throw_on_copy( ARG(T) ) ;
passed = false ;
try
{
// This should attempt to swap optionals and fail at opt0.reset(*opt1)
// opt0 should be left uninitialized and opt1 unchanged.
swap(opt0,opt1);
passed = true ;
}
catch ( ... ) {}
BOOST_CHECK(!passed);
check_uninitialized(opt0);
check_initialized(opt1);
check_value(opt1,a,b);
}
//
// This verifies relational operators.
//
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);
optional<T> def0 ;
optional<T> def1 ;
optional<T> opt0(v0);
optional<T> opt1(v1);
optional<T> opt2(v2);
// Check identity
BOOST_CHECK ( def0 == def0 ) ;
BOOST_CHECK ( opt0 == opt0 ) ;
BOOST_CHECK ( !(def0 != def0) ) ;
BOOST_CHECK ( !(opt0 != opt0) ) ;
// If both are uininitalized they compare equal
BOOST_CHECK ( def0 == def1 ) ;
BOOST_CHECK ( !(def0 != def1) ) ;
// If only one is initialized they compare unequal
BOOST_CHECK ( def0 != opt0 ) ;
BOOST_CHECK ( !(def1 == opt1) ) ;
// If both are initialized, values are compared
BOOST_CHECK ( opt0 != opt1 ) ;
BOOST_CHECK ( opt1 == opt2 ) ;
}
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) );
test_relops( ARG(double) ) ;
}
void test_with_class_type()
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
test_basics( ARG(X) );
test_direct_value_manip( ARG(X) );
test_uninitialized_access( ARG(X) );
test_throwing_direct_init( ARG(X) );
test_throwing_val_assign_on_uninitialized( ARG(X) );
test_throwing_val_assign_on_initialized( ARG(X) );
test_throwing_copy_initialization( ARG(X) );
test_throwing_assign_to_uninitialized( ARG(X) );
test_throwing_assign_to_initialized( ARG(X) );
test_no_throwing_swap( ARG(X) );
test_throwing_swap( ARG(X) );
test_relops( ARG(X) ) ;
BOOST_CHECK ( X::count == 0 ) ;
}
int eat ( char ) { return 1 ; }
int eat ( int ) { return 1 ; }
int eat ( void const* ) { return 1 ; }
template<class T> int eat ( T ) { return 0 ; }
//
// This verifies that operator safe_bool() behaves properly.
//
template<class T>
void test_no_implicit_conversions_impl( T const& )
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
optional<T> def ;
BOOST_CHECK ( eat(def) == 0 ) ;
}
void test_no_implicit_conversions()
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
char c = 0 ;
int i = 0 ;
void const* p = 0 ;
test_no_implicit_conversions_impl(c);
test_no_implicit_conversions_impl(i);
test_no_implicit_conversions_impl(p);
}
struct A {} ;
void test_conversions()
{
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR
char c = 20 ;
optional<char> opt0(c);
optional<int> opt1(opt0);
BOOST_CHECK(*opt1 == static_cast<int>(c));
#endif
#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT
float f = 21.22f ;
double d = f ;
optional<float> opt2(f) ;
optional<double> opt3 ;
opt3 = opt2 ;
BOOST_CHECK(*opt3 == d);
#endif
}
int test_main( int, char* [] )
{
try
{
test_with_class_type();
test_with_builtin_types();
test_no_implicit_conversions();
test_conversions();
}
catch ( ... )
{
BOOST_ERROR("Unexpected Exception caught!");
}
return 0;
}

View File

@ -1,28 +0,0 @@
// (C) 2003, Fernando Luis Cacciola Carballal.
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#include "boost/optional.hpp"
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void test_deep_constantness()
{
boost::optional<int> opt ;
boost::optional<int> const copt ;
*copt = opt ; // Cannot assign to "int const&"
}

View File

@ -1,26 +0,0 @@
// (C) 2003, Fernando Luis Cacciola Carballal.
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#include "boost/optional.hpp"
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void test_no_direct_value_assignment()
{
boost::optional<int> opt(3) ;
opt = 4 ; // Cannot assign "int" to "optional<int>"
}

View File

@ -1,36 +0,0 @@
// (C) 2003, Fernando Luis Cacciola Carballal.
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#include "boost/optional.hpp"
//
// THIS TEST SHOULD FAIL TO COMPILE
//
#if BOOST_WORKAROUND( BOOST_INTEL_CXX_VERSION, <= 700) // Intel C++ 7.0
// Interl C++ 7.0 incorrectly accepts the initialization "boost::optional<int> opt = 3"
// even though the ctor is explicit (c.f. 12.3.1.2), so the test uses another form of
// copy-initialization: argument-passing (8.5.12)
void helper ( boost::optional<int> ) ;
void test_explicit_constructor()
{
helper(3) ; // ERROR: Ctor is explicit.
}
#else
void test_explicit_constructor()
{
boost::optional<int> opt = 3 ; // ERROR: Ctor is explicit.
}
#endif

View File

@ -1,29 +0,0 @@
// (C) 2003, Fernando Luis Cacciola Carballal.
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#include "boost/optional.hpp"
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void test_no_implicit_conversion()
{
boost::optional<int> opt(1) ;
// You can compare against 0 or against another optional<>,
// but not against another value
if ( opt == 1 ) ;
}

View File

@ -1,28 +0,0 @@
// (C) 2003, Fernando Luis Cacciola Carballal.
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#include<string>
#include "boost/optional.hpp"
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void test_no_unsupported_conversion()
{
boost::optional<int> opt1(1) ;
boost::optional< std::string > opt2( opt1 ) ; // Cannot convert from "int" to "std::string"
}

View File

@ -1,29 +0,0 @@
// (C) 2003, Fernando Luis Cacciola Carballal.
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// You are welcome to contact the author at:
// fernando_cacciola@hotmail.com
//
#include<string>
#include "boost/optional.hpp"
//
// THIS TEST SHOULD FAIL TO COMPILE
//
void test_no_unsupported_conversion()
{
boost::optional<int> opt1(1) ;
boost::optional< std::string > opt2 ;
opt2 = opt1 ; // Cannot convert from "int" to "std::string"
}