diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 new file mode 100644 index 0000000..95574ce --- /dev/null +++ b/doc/Jamfile.v2 @@ -0,0 +1,28 @@ +# Boost.Optional +# +# Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal +# +# Distributed under 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) + + +# Quickbook +# ----------------------------------------------------------------------------- + +import quickbook ; + +xml optional + : + optional.qbk + ; + +boostbook standalone + : + optional + : + toc.max.depth=1 + toc.section.depth=1 + chunk.section.depth=1 + ; + diff --git a/doc/acknowledgments.qbk b/doc/acknowledgments.qbk new file mode 100644 index 0000000..117a468 --- /dev/null +++ b/doc/acknowledgments.qbk @@ -0,0 +1,60 @@ +[/ + Boost.Optional + + Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal + + Distributed under 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) +] + + +[section Acknowledgments] + +[heading Pre-formal review] + +* Peter Dimov suggested the name 'optional', and was the first to point out +the need for aligned storage. +* Douglas Gregor developed 'type_with_alignment', and later Eric Friedman +coded 'aligned_storage', which are the core of the optional class +implementation. +* Andrei Alexandrescu and Brian Parker also worked with aligned storage +techniques and their work influenced the current implementation. +* Gennadiy Rozental made extensive and important comments which shaped the +design. +* 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. +* Eric Friedman helped understand the issues involved with aligned storage, +move/copy operations and exception safety. +* Many others have participated with useful comments: Aleksey Gurotov, +Kevlin Henney, David Abrahams, and others I can't recall. + +[heading Post-formal review] + +* 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. +* 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. +* 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. +* Joel de Guzman noticed that optional<> can be seen as an API on top of +variant. +* Dave Gomboc explained the meaning and usage of the Haskell analog to +optional<>: the Maybe type constructor (analogy originally pointed out by +David Sankel). +* Other comments were posted by Vincent Finn, Anthony Williams, Ed Brey, +Rob Stewart, and others. +* Joel de Guzman made the case for the support of references and helped +with the proper semantics. +* Mat Marcus shown the virtues of a value-oriented interface, influencing +the current design, and contributed the idea of "none". + +[endsect] + diff --git a/doc/dependencies.qbk b/doc/dependencies.qbk new file mode 100644 index 0000000..6aa0eb5 --- /dev/null +++ b/doc/dependencies.qbk @@ -0,0 +1,17 @@ +[/ + Boost.Optional + + Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal + + Distributed under 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) +] + + +[section Dependencies and Portability] + +The implementation uses `type_traits/alignment_of.hpp` and +`type_traits/type_with_alignment.hpp` + +[endsect] \ No newline at end of file diff --git a/doc/development.qbk b/doc/development.qbk new file mode 100644 index 0000000..cd00e45 --- /dev/null +++ b/doc/development.qbk @@ -0,0 +1,251 @@ +[/ + Boost.Optional + + Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal + + Distributed under 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) +] + +[section Development] + +[section The models] + +In C++, we can ['declare] an object (a variable) of type `T`, and we can give this +variable an ['initial value] (through an ['initializer]. (c.f. 8.5)). +When a declaration includes a non-empty initializer (an initial value is given), +it is said that the object has been initialized. +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 +[*uninitialized]. Its actual value exist but has an ['indeterminate initial value] +(c.f. 8.5.9). +`optional` 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` 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 ['undefined behavior] to try to access the value of an uninitialized +optional. An uninitialized optional can be assigned 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 ['uninitialized]. + +In C++ there is no formal notion of uninitialized objects, which means that +objects always have an initial value even if indeterminate. +As discussed on the previous section, this has a drawback because you need +additional information to tell if an object has been effectively initialized. +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 ['nil_t]—were `nil_t` is some stateless POD-can be modeled in modern +languages as a [*discriminated union] of T and nil_t. Discriminated unions are +often called ['variants]. A variant has a ['current type], which in our case is either +`T` or `nil_t`. +Using the __BOOST_VARIANT__ library, this model can be implemented in terms of `boost::variant`. +There is precedent for a discriminated union as a model for an optional value: +the __HASKELL__ [*Maybe] built-in type constructor. Thus, a discriminated union +`T+nil_t` serves as a conceptual foundation. + +A `variant` follows naturally from the traditional idiom of extending +the range of possible values adding an additional sentinel value with the +special meaning of ['Nothing]. However, this additional ['Nothing] value is largely +irrelevant for our purpose since our goal is to formalize the notion of +uninitialized objects and, while a special extended value can be used to convey +that meaning, it is not strictly necessary in order to do so. + +The observation made in the last paragraph about the irrelevant nature of the +additional `nil_t` with respect to [_purpose] of `optional` suggests an +alternative model: a ['container] that either has a value of `T` or nothing. + +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. + +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. +For instance, these models show the ['exact] semantics required for a wrapper +of optional values: + +Discriminated-union: + +* [*deep-copy] semantics: copies of the variant implies copies of the value. +* [*deep-relational] semantics: comparisons between variants matches both +current types and values +* If the variant's current type is `T`, it is modeling an ['initialized] optional. +* If the variant's current type is not `T`, it is modeling an ['uninitialized] +optional. +* Testing if the variant's current type is `T` models testing if the optional +is initialized +* 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 + +Single-element container: + +* [*deep-copy] semantics: copies of the container implies copies of the value. +* [*deep-relational] semantics: comparisons between containers compare container +size and if match, contained value +* If the container is not empty (contains an object of type `T`), it is modeling +an ['initialized] optional. +* If the container is empty, it is modeling an ['uninitialized] optional. +* Testing if the container is empty models testing if the optional is +initialized +* Trying to extract a `T` from an empty container models the undefined behavior +of trying to access the value of an uninitialized optional + +[endsect] + +[section The semantics] + +Objects of type `optional` are intended to be used in places where objects of +type `T` would but which might be uninitialized. Hence, `optional`'s purpose is +to formalize the additional possibly uninitialized state. +From the perspective of this role, `optional` can have the same operational +semantics of `T` plus the additional semantics corresponding to this special +state. +As such, `optional` could be thought of as a ['supertype] of `T`. Of course, we +can't do that in C++, so we need to compose the desired semantics using a +different mechanism. +Doing it the other way around, that is, making `optional` a ['subtype] 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. + +We can draw from the purpose of `optional` the required basic semantics: + +* [*Default Construction:] To introduce a formally uninitialized wrapped +object. +* [*Direct Value Construction via copy:] To introduce a formally initialized +wrapped object whose value is obtained as a copy of some object. +* [*Deep Copy Construction:] To obtain a new yet equivalent wrapped object. +* [*Direct Value Assignment (upon initialized):] To assign a value to the +wrapped object. +* [*Direct Value Assignment (upon uninitialized):] To initialize the wrapped +object with a value obtained as a copy of some object. +* [*Assignment (upon initialized):] To assign to the wrapped object the value +of another wrapped object. +* [*Assignment (upon uninitialized):] To initialize the wrapped object with +value of another wrapped object. +* [*Deep Relational Operations (when supported by the type T):] To compare +wrapped object values taking into account the presence of uninitialized states. +* [*Value access:] To unwrap the wrapped object. +* [*Initialization state query:] To determine if the object is formally +initialized or not. +* [*Swap:] To exchange wrapped objects. (with whatever exception safety +guarantees are provided by `T`'s swap). +* [*De-initialization:] To release the wrapped object (if any) and leave the +wrapper in the uninitialized state. + +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. + +[endsect] + +[section The Interface] + +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: 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` +extends such a set of values with a new value for which most +(otherwise valid) operations are not defined in terms of `T`. + +Furthermore, since `optional` 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`. + +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. + +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). + +Also, the presence of the possibly uninitialized state requires additional +operations not provided by `T` itself which are supported by a special interface. + +[heading Lexically-hinted Value Access in the presence of possibly +untitialized optional objects: The operators * and ->] + +A relevant feature of a pointer is that it can have a [*null pointer value]. +This is a ['special] 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. + +This meaning of the null pointer value allowed pointers to became a ['de +facto] 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 ['refer] to optional (that is, +possibly inexistent) objects; particularly as optional arguments to a +function, but also quite often as optional data members. + +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: `( *p = 2 )` and `( p->foo() )`, +implicitly convey the notion of optionality, and this information is tied to +the ['syntax] 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. + +Such a ['de facto] idiom for referring to optional objects can be formalized +in the form of a concept: the __OPTIONAL_POINTEE__ concept. +This concept captures the syntactic usage of operators `*`, `->` and +conversion to `bool` to convey the notion of optionality. + +However, pointers are good to [_refer] 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. + +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` 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 +__OPTIONAL_POINTEE__ concept incarnated by pointers. + + +[heading Optional as a model of OptionalPointee] + +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. + +[warning +However, it is particularly important to note that `optional<>` objects +are not pointers. [_`optional<>` is not, and does not model, a pointer]. +] + +For instance, `optional<>` does not have shallow-copy so does not alias: +two different optionals never refer to the ['same] value unless `T` itself is +a reference (but may have ['equivalent] values). +The difference between an `optional` and a pointer must be kept in mind, +particularly because the semantics of relational operators are different: +since `optional` 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. +As a result, you might be able to replace `optional` 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 __FUNCTION_EQUAL_POINTEES__ and __FUNCTION_LESS_POINTEES__ instead. + +[endsect] + +[endsect] diff --git a/doc/examples.qbk b/doc/examples.qbk new file mode 100644 index 0000000..4bd7f6a --- /dev/null +++ b/doc/examples.qbk @@ -0,0 +1,102 @@ +[/ + Boost.Optional + + Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal + + Distributed under 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) +] + + +[section Examples] + +[section Optional return values] + + optional get_async_input() + { + if ( !queue.empty() ) + return optional(queue.top()); + else return optional(); // uninitialized + } + + void receive_async_message() + { + optional rcv ; + // The safe boolean conversion from 'rcv' is used here. + while ( (rcv = get_async_input()) && !timeout() ) + output(*rcv); + } + +[endsect] + +[section Optional local variables] + + optional 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!"); + +[endsect] + +[section Optional data members] + + 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 m_clipping_rect ; + + }; + +[endsect] + +[section Bypassing expensive unnecessary default construction] + + class ExpensiveCtor { ... } ; + class Fred + { + Fred() : mLargeVector(10000) {} + + std::vector< optional > mLargeVector ; + } ; + +[endsect] + +[endsect] + + diff --git a/doc/html/HTML.manifest b/doc/html/HTML.manifest new file mode 100644 index 0000000..759b268 --- /dev/null +++ b/doc/html/HTML.manifest @@ -0,0 +1,14 @@ +index.html +boost_optional/development.html +boost_optional/synopsis.html +boost_optional/detailed_semantics.html +boost_optional/examples.html +boost_optional/optional_references.html +boost_optional/rebinding_semantics_for_assignment_of_optional_references.html +boost_optional/in_place_factories.html +boost_optional/a_note_about_optional_bool_.html +boost_optional/exception_safety_guarantees.html +boost_optional/type_requirements.html +boost_optional/implementation_notes.html +boost_optional/dependencies_and_portability.html +boost_optional/acknowledgments.html diff --git a/doc/html/boost_optional/a_note_about_optional_bool_.html b/doc/html/boost_optional/a_note_about_optional_bool_.html new file mode 100644 index 0000000..42d69df --- /dev/null +++ b/doc/html/boost_optional/a_note_about_optional_bool_.html @@ -0,0 +1,84 @@ + + + +A note about + optional<bool> + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ optional<bool> should + be used with special caution and consideration. +

+

+ First, it is functionally similar to a tristate boolean (false,maybe,true) + —such as boost::tribool— + except that in a tristate boolean, the maybe state represents + a valid value, unlike the corresponding state of an uninitialized + optional<bool>. It + should be carefully considered if an optional<bool> + instead of a tribool is really + needed. +

+

+ Second, optional<> + provides an implicit conversion to bool. + This conversion refers to the initialization state and not to the contained + value. Using optional<bool> can + lead to subtle errors due to the implicit bool + conversion: +

+
+void foo ( bool v ) ;
+void bar()
+{
+    optional<bool> v = try();
+
+    // The following intended to pass the value of 'v' to foo():
+    foo(v);
+    // But instead, the initialization state is passed
+    // due to a typo: it should have been foo(*v).
+}
+
+

+ The only implicit conversion is to bool, + and it is safe in the sense that typical integral promotions don't apply (i.e. + if foo() + takes an int instead, it won't + compile). +

+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/acknowledgments.html b/doc/html/boost_optional/acknowledgments.html new file mode 100644 index 0000000..e2cc05a --- /dev/null +++ b/doc/html/boost_optional/acknowledgments.html @@ -0,0 +1,122 @@ + + + +Acknowledgments + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHome +
+
+ +

+ + Pre-formal + review +

+
    +
  • + Peter Dimov suggested the name 'optional', and was the first to point out + the need for aligned storage. +
  • +
  • + Douglas Gregor developed 'type_with_alignment', and later Eric Friedman coded + 'aligned_storage', which are the core of the optional class implementation. +
  • +
  • + Andrei Alexandrescu and Brian Parker also worked with aligned storage techniques + and their work influenced the current implementation. +
  • +
  • + Gennadiy Rozental made extensive and important comments which shaped the + design. +
  • +
  • + 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. +
  • +
  • + Eric Friedman helped understand the issues involved with aligned storage, + move/copy operations and exception safety. +
  • +
  • + Many others have participated with useful comments: Aleksey Gurotov, Kevlin + Henney, David Abrahams, and others I can't recall. +
  • +
+

+ + Post-formal + review +

+
    +
  • + 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. +
  • +
  • + 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. +
  • +
  • + 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. +
  • +
  • + Joel de Guzman noticed that optional<> can be seen as an API on top + of variant<T,nil_t>. +
  • +
  • + Dave Gomboc explained the meaning and usage of the Haskell analog to optional<>: + the Maybe type constructor (analogy originally pointed out by David Sankel). +
  • +
  • + Other comments were posted by Vincent Finn, Anthony Williams, Ed Brey, Rob + Stewart, and others. +
  • +
  • + Joel de Guzman made the case for the support of references and helped with + the proper semantics. +
  • +
  • + Mat Marcus shown the virtues of a value-oriented interface, influencing the + current design, and contributed the idea of "none". +
  • +
+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHome +
+ + diff --git a/doc/html/boost_optional/dependencies_and_portability.html b/doc/html/boost_optional/dependencies_and_portability.html new file mode 100644 index 0000000..ccc0d2c --- /dev/null +++ b/doc/html/boost_optional/dependencies_and_portability.html @@ -0,0 +1,46 @@ + + + +Dependencies + and Portability + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ The implementation uses type_traits/alignment_of.hpp and + type_traits/type_with_alignment.hpp +

+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html new file mode 100644 index 0000000..bbebfd7 --- /dev/null +++ b/doc/html/boost_optional/detailed_semantics.html @@ -0,0 +1,1703 @@ + + + +Detailed Semantics + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ 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: * If the entry reads: optional<T(not a ref)>, the description corresponds only to the + case where T is not of reference + type. * If the entry reads: optional<T&>, + the description corresponds only to the case where T + is of reference type. * If the entry reads: optional<T>, + the description is the same for both cases. +

+
+ + + + + +
[Note]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. +

+

+

+
+

+ space +

+

+ + optional + class member functions +

+

+ space +

+

+

+
+

+

+

+ optional<T>::optional(); +

+

+

+
+
    +
  • +Effect: Default-Constructs an optional. +
  • +
  • +Postconditions:*this is uninitialized. +
  • +
  • +Throws: Nothing. +
  • +
  • + Notes: T's default constructor is not + called. +
  • +
  • +Example:
    +optional<T> def ;
    +assert ( !def ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ optional<T>::optional( none_t ); +

+

+

+
+
    +
  • +Effect: Constructs an optional + uninitialized. +
  • +
  • +Postconditions:*this is uninitialized. +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes:T's + default constructor is not called. + The expression boost::none denotes an instance of boost::none_t that can be used as the parameter. +
  • +
  • +Example:
    +#include <boost/none.hpp>
    +optional<T> n(none) ;
    +assert ( !n ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

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

+

+

+
+
    +
  • +Effect: Directly-Constructs an optional. +
  • +
  • +Postconditions:*this is initialized + and its value is acopy of v. +
  • +
  • +Throws: Whatever T::T( + T const& ) throws. +
  • +
  • +Notes: T::T( + T const& ) is + called. +
  • +
  • +Exception Safety: Exceptions can only be + thrown during T::T( T + const& + ); in that case, this constructor + has no effect. +
  • +
  • +Example:
    +T v;
    +optional<T> opt(v);
    +assert ( *opt == v ) ;
    +
    +
  • +
+

+ space +

+
+

+

+

+ optional<T&>::optional( T& ref ) +

+

+

+
+
    +
  • +Effect: Directly-Constructs an optional. +
  • +
  • +Postconditions:*this is initialized + and its value is an instance of an internal type wrapping the reference + ref. +
  • +
  • +Throws: Nothing. +
  • +
  • +Example:
    +T v;
    +T& vref = v ;
    +optional<T&> opt(vref);
    +assert ( *opt == v ) ;
    +++ v ; // mutate referee
    +assert (*opt == v);
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ optional<T (not a ref)>::optional( bool condition, + T const& v ) ; +

+

+

+
+
+

+

+

+ optional<T&> + ::optional( bool condition, + T& + v ) + ; +

+

+

+
+
  • + If condition is true, same as: +
+
+

+

+

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

+

+

+
+
+

+

+

+ optional<T&> + ::optional( T& + v ) +

+

+

+
+
  • + otherwise, same as: +
+
+

+

+

+ optional<T [#(not a + ref)]>::optional() +

+

+

+
+
+

+

+

+ optional<T&> + ::optional() +

+

+

+
+

+ space +

+

+

+
+

+

+

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

+

+

+
+
    +
  • +Effect: Copy-Constructs an optional. +
  • +
  • +Postconditions: If rhs is initialized, + *this + is initialized and its value is a copy of the value + of rhs; else *this is uninitialized. +
  • +
  • +Throws: Whatever T::T( + T const& ) throws. +
  • +
  • +Notes: If rhs is initialized, T::T(T const& ) is + called. +
  • +
  • +Exception Safety: Exceptions can only be + thrown during T::T( T + const& + ); in that case, this constructor + has no effect. +
  • +
  • +Example:
    +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 ) ;
    +
    +
  • +
+

+ space +

+
+

+

+

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

+

+

+
+
    +
  • +Effect: Copy-Constructs an optional. +
  • +
  • +Postconditions: If rhs + is initialized, *this + is initialized and its value is another reference to the same object referenced + by *rhs; + else *this + is uninitialized. +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes: If rhs + is initialized, both *this + and *rhs + will reefer to the same object (they alias). +
  • +
  • +Example:
    +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 ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

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

+

+

+
+
    +
  • +Effect: Copy-Constructs an optional. +
  • +
  • +Postconditions: If rhs + is initialized, *this + is initialized and its value is a copy of the value + of rhs converted to type T; + else *this + is uninitialized. +
  • +
  • +Throws: Whatever T::T( + U const& ) throws. +
  • +
  • +Notes: T::T( + U const& ) is + called if rhs is initialized, + which requires a valid conversion from U + to T. +
  • +
  • +Exception Safety: Exceptions can only be + thrown during T::T( U + const& + ); in that case, this constructor + has no effect. +
  • +
  • +Example:
    +optional<double> x(123.4);
    +assert ( *x == 123.4 ) ;
    +
    +optional<int> y(x) ;
    +assert( *y == 123 ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ template<InPlaceFactory> + explicit optional<T + (not a ref)>::optional( InPlaceFactory const& f ); +

+

+

+
+
+

+

+

+ template<TypedInPlaceFactory> + explicit optional<T + (not a ref)>::optional( TypedInPlaceFactory const& f ); +

+

+

+
+
    +
  • +Effect: Constructs an optional + with a value of T obtained + from the factory. +
  • +
  • +Postconditions: *this is initialized + and its value is directly given from the factory f (i.e., the value is + not copied). +
  • +
  • +Throws: Whatever the T + constructor called by the factory throws. +
  • +
  • +Notes: See In-Place + Factories +
  • +
  • +Exception Safety: Exceptions can only be + thrown during the call to the T + constructor used by the factory; in that case, this constructor has no effect. +
  • +
  • +Example:
    +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 ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

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

+

+

+
+
    +
  • +Effect: Assigns the value rhs to an optional. +
  • +
  • +Postconditions: *this is initialized and its value is a copy + of rhs. +
  • +
  • +Throws: Whatever T::operator=( T const& ) or + T::T(T + const&) + throws. +
  • +
  • +Notes: If *this was initialized, T's + assignment operator is used, otherwise, its copy-constructor is used. +
  • +
  • +Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned + (it is up to T's operator=()). + If *this + is initially uninitialized and T's + copy constructor fails, *this is left properly uninitialized. +
  • +
  • +Example:
    +T x;
    +optional<T> def ;
    +optional<T> opt(x) ;
    +
    +T y;
    +def = y ;
    +assert ( *def == y ) ;
    +opt = y ;
    +assert ( *opt == y ) ;
    +
    +
  • +
+

+ space +

+
+

+

+

+ optional<T&>& + optional<T&>::operator= ( T& + const& + rhs ) + ; +

+

+

+
+
    +
  • +Effect: (Re)binds thee wrapped reference. +
  • +
  • +Postconditions: *this is initialized and it references the + same object referenced by rhs. +
  • +
  • +Notes: If *this was initialized, is is rebound + to the new object. See here for + details on this behavior. +
  • +
  • +Example:
    +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 ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

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

+

+

+
+
    +
  • +Effect: Assigns another optional + to an optional. +
  • +
  • +Postconditions: If rhs + is initialized, *this + is initialized and its value is a copy of the value + of rhs; else *this is uninitialized. +
  • +
  • +Throws: Whatever T::operator( T const&) or T::T( + T const& ) throws. +
  • +
  • +Notes: If both *this and rhs + are initially initialized, T's + assignment operator is used. If *this is initially initialized but rhs is uninitialized, T's + [destructor] is called. If *this is initially uninitialized but rhs is initialized, T's + copy constructor is called. +
  • +
  • +Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned (it is up to T's + operator=()). + If *this + is initially uninitialized and T's + copy constructor fails, *this is left properly uninitialized. +
  • +
  • +Example:
    +T v;
    +optional<T> opt(v);
    +optional<T> def ;
    +
    +opt = def ;
    +assert ( !def ) ;
    +// previous value (copy of 'v') destroyed from within 'opt'.
    +
    +
  • +
+

+ space +

+
+

+

+

+ optional<T&> + & optional<T&>::operator= ( optional<T&> const& rhs ) ; +

+

+

+
+
    +
  • +Effect: (Re)binds thee wrapped reference. +
  • +
  • +Postconditions: If *rhs is initialized, *this is initialized and it references the + same object referenced by *rhs; otherwise, *this is uninitialized (and references no object). +
  • +
  • +Notes: If *this was initialized and so is *rhs, this + is is rebound to the new object. See here + for details on this behavior. +
  • +
  • +Example:
    +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 ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ template<U> optional& + optional<T (not a ref)>::operator= ( optional<U> const& rhs ) ; +

+

+

+
+
    +
  • +Effect: Assigns another convertible optional + to an optional. +
  • +
  • +Postconditions: If rhs + is initialized, *this + is initialized and its value is a copy of the value + of rhsconverted + to type T; else *this is uninitialized. +
  • +
  • +Throws: Whatever T::operator=( U const& ) or + T::T( U + const& + ) throws. +
  • +
  • +Notes: If both *this and rhs are initially initialized, T's assignment operator + (from U) is used. If *this is initially + initialized but rhs is uninitialized, + T's destructor + is called. If *this + is initially uninitialized but rhs is initialized, T's + converting constructor (from U) + is called. +
  • +
  • +Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned (it is up to T's + operator=()). + If *this + is initially uninitialized and T's + converting constructor fails, *this is left properly uninitialized. +
  • +
  • +Example:
    +T v;
    +optional<T> opt0(v);
    +optional<U> opt1;
    +
    +opt1 = opt0 ;
    +assert ( *opt1 == static_cast<U>(v) ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

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

+

+

+
+
  • +Deprecated: same as operator= ( T + const& + v) ; +
+

+ space +

+

+

+
+

+

+

+ void optional<T>::reset() ; +

+

+

+
+
  • +Deprecated: Same as operator=( detail::none_t ); +
+

+ space +

+

+

+
+

+

+

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

+

+

+
+
+

+

+

+ T& + optional<T (not a ref)>::operator*(); +

+

+

+
+
+

+

+

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

+

+

+
+
+

+

+

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

+

+

+
+
+

+

+

+ inline T + const& + get ( + optional<T (not a ref)> const& ) ; +

+

+

+
+
+

+

+

+ inline T& get ( optional<T + (not a ref)> + &) ; +

+

+

+
+
    +
  • +Requirements:*this is initialized +
  • +
  • +Returns: A reference to the contained value +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes: The requirement is asserted via + BOOST_ASSERT(). +
  • +
  • +Example:
    +T v ;
    +optional<T> opt ( v );
    +T const& u = *opt;
    +assert ( u == v ) ;
    +T w ;
    +*opt = w ;
    +assert ( *opt == w ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

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

+

+

+
+
+

+

+

+ T& + optional<T (not a ref)>::get_value_or( T& + default ) + ; +

+

+

+
+
+

+

+

+ inline T + const& + get_optional_value_or ( + optional<T (not a ref)> const& o, T const& default ) ; +

+

+

+
+
+

+

+

+ inline T& get_optional_value_or + ( optional<T + (not a ref)>& + o, + T& + default ) + ; +

+

+

+
+
    +
  • +Returns: A reference to the contained value, + if any, or default. +
  • +
  • +Throws: Nothing. +
  • +
  • +Example:
    +T v, z ;
    +optional<T> def;
    +T const& y = def.get_value_or(z);
    +assert ( y == z ) ;
    +
    +optional<T> opt ( v );
    +T const& u = get_optional_value_or(opt,z);
    +assert ( u == v ) ;
    +assert ( u != z ) ;
    +
    +
  • +
+

+ space +

+
+

+

+

+ T const& optional<T&>::operator*() const ; +

+

+

+
+
+

+

+

+ T & + optional<T&>::operator*(); +

+

+

+
+
+

+

+

+ T const& optional<T&>::get() const ; +

+

+

+
+
+

+

+

+ T& + optional<T&>::get() ; +

+

+

+
+
+

+

+

+ inline T + const& + get ( + optional<T&> + const& + ) ; +

+

+

+
+
+

+

+

+ inline T& get ( optional<T&> &) + ; +

+

+

+
+
    +
  • +Requirements: *this is initialized +
  • +
  • +Returns:The + reference contained. +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes: The requirement is asserted via + BOOST_ASSERT(). +
  • +
  • +Example:
    +T v ;
    +T& vref = v ;
    +optional<T&> opt ( vref );
    +T const& vref2 = *opt;
    +assert ( vref2 == v ) ;
    +++ v ;
    +assert ( *opt == v ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ T const* optional<T + (not a ref)>::get_ptr() const ; +

+

+

+
+
+

+

+

+ T* + optional<T (not a ref)>::get_ptr() ; +

+

+

+
+
+

+

+

+ inline T + const* + get_pointer ( + optional<T (not a ref)> const& ) ; +

+

+

+
+
+

+

+

+ inline T* get_pointer + ( optional<T + (not a ref)> + &) ; +

+

+

+
+
    +
  • +Returns: If *this is initialized, a pointer to the contained + value; else 0 (null). +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes: The contained value is permanently + stored within *this, + so you should not hold nor delete this pointer +
  • +
  • +Example:
    +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) ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ T const* optional<T + (not a ref)>::operator ->() + const ; +

+

+

+
+
+

+

+

+ T* + optional<T (not a ref)>::operator + ->() ; +

+

+

+
+
    +
  • +Requirements: *this is initialized. +
  • +
  • +Returns: A pointer to the contained value. +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes: The requirement is asserted via + BOOST_ASSERT(). +
  • +
  • +Example:
    +struct X { int mdata ; } ;
    +X x ;
    +optional<X> opt (x);
    +opt->mdata = 2 ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ optional<T>::operator unspecified-bool-type() const ; +

+

+

+
+
    +
  • +Returns: An unspecified value which if used + on a boolean context is equivalent to (get() != 0) +
  • +
  • +Throws: Nothing. +
  • +
  • +Example:
    +optional<T> def ;
    +assert ( def == 0 );
    +optional<T> opt ( v ) ;
    +assert ( opt );
    +assert ( opt != 0 );
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ bool optional<T>::operator!() ; +

+

+

+
+
    +
  • +Returns: If *this is uninitialized, true; + else false. +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes: This operator is provided for those + compilers which can't use the unspecified-bool-type operator + in certain boolean contexts. +
  • +
  • +Example:
    +optional<T> opt ;
    +assert ( !opt );
    +*opt = some_T ;
    +
    +// Notice the "double-bang" idiom here.
    +assert ( !!opt ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ bool optional<T>::is_initialized() const ; +

+

+

+
+
    +
  • +Returns: true + if the optional is initialized, + false otherwise. +
  • +
  • +Throws: Nothing. +
  • +
  • +Example:
    +optional<T> def ;
    +assert ( !def.is_initialized() );
    +optional<T> opt ( v ) ;
    +assert ( opt.is_initialized() );
    +
    +
  • +
+

+ space +

+

+ + Free functions +

+

+ space +

+

+

+
+

+

+

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

+

+

+
+
    +
  • +Returns: optional<T>(v) for + the deduced type T + of v. +
  • +
  • +Example:
    +template<class T> void foo ( optional<T> const& opt ) ;
    +
    +foo ( make_optional(1+1) ) ; // Creates an optional<int>
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ optional<T (not a ref)> make_optional( bool condition, + T const& v ) +

+

+

+
+
    +
  • +Returns: optional<T>(condition,v) for + the deduced type T + of v. +
  • +
  • +Example:
    +optional<double> calculate_foo()
    +{
    +  double val = compute_foo();
    +  return make_optional(is_not_nan_and_finite(val),val);
    +}
    +
    +optional<double> v = calculate_foo();
    +if ( !v )
    +  error("foo wasn't computed");
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ bool operator + == ( optional<T> const& x, optional<T> const& y ); +

+

+

+
+
    +
  • +Returns: If both x + and y are initialized, (*x == + *y). If only x + or y is initialized, false. If both are uninitialized, true. +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes: Pointers have shallow relational + operators while optional + has deep relational operators. Do not use operator + == directly in generic code which + expect to be given either an optional<T> + or a pointer; use equal_pointees() + instead +
  • +
  • +Example:
    +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 ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ bool operator + < ( + optional<T> const& x, optional<T> const& y ); +

+

+

+
+
    +
  • +Returns: If y + is not initialized, false. If + y is initialized and x is not initialized, true. + If both x and y are initialized, (*x < *y). +
  • +
  • +Throws: Nothing. +
  • +
  • +Notes: Pointers have shallow relational + operators while optional + has deep relational operators. Do not use operator + < directly in generic code which + expect to be given either an optional<T> + or a pointer; use less_pointees() + instead. +
  • +
  • +Example:
    +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 ) ;
    +
    +
  • +
+

+ space +

+

+

+
+

+

+

+ bool operator + != ( optional<T> const& x, optional<T> const& y ); +

+

+

+
+
    +
  • +Returns: !( + x == + y ); +
  • +
  • +Throws: Nothing. +
  • +
+

+ space +

+

+

+
+

+

+

+ bool operator + > ( + optional<T> const& x, optional<T> const& y ); +

+

+

+
+
    +
  • +Returns: ( + y < + x ); +
  • +
  • +Throws: Nothing. +
  • +
+

+ space +

+

+

+
+

+

+

+ bool operator + <= ( + optional<T> const& x, optional<T> const& y ); +

+

+

+
+
    +
  • +Returns: !( + y<x ); +
  • +
  • +Throws: Nothing. +
  • +
+

+ space +

+

+

+
+

+

+

+ bool operator + >= ( + optional<T> const& x, optional<T> const& y ); +

+

+

+
+
    +
  • +Returns: !( + x<y ); +
  • +
  • +Throws: Nothing. +
  • +
+

+ space +

+

+

+
+

+

+

+ void swap + ( optional<T>& x, optional<T>& y + ); +

+

+

+
+
    +
  • +Effect: If both x + and y are initialized, calls + swap(*x,*y) using std::swap. + If only one is initialized, say x, + calls: y.reset(*x); x.reset(); If none is initialized, does nothing. +
  • +
  • +Postconditions: The states of x and y + interchanged. +
  • +
  • +Throws: If both are initialized, whatever + swap(T&,T&) + throws. If only one is initialized, whatever T::T ( + T const& ) throws. +
  • +
  • +Notes: If both are initialized, swap(T&,T&) is used unqualified but with std::swap + introduced in scope. If only one is initialized, T::~T() + and T::T( T + const& + ) is called. +
  • +
  • +Exception Safety: If both are initialized, + this operation has the exception safety guarantees of swap(T&,T&). + If only one is initialized, it has the same basic guarantee as optional<T>::reset( T const& ). +
  • +
  • +Example:
    +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 );
    +
    +
  • +
+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/development.html b/doc/html/boost_optional/development.html new file mode 100644 index 0000000..c013432 --- /dev/null +++ b/doc/html/boost_optional/development.html @@ -0,0 +1,415 @@ + + + +Development + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ In C++, we can declare an object (a variable) of type + T, and we can give this variable + an initial value (through an initializer. + (c.f. 8.5)). When a declaration includes a non-empty initializer (an initial + value is given), it is said that the object has been initialized. 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 + uninitialized. Its actual value exist but + has an indeterminate initial value (c.f. 8.5.9). optional<T> 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 formally + uninitialized. A formally uninitialized optional object has conceptually + no value at all and this situation can be tested at runtime. It is formally + undefined behavior to try to access the value of an + uninitialized optional. An uninitialized optional can be assigned 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 uninitialized. +

+

+ In C++ there is no formal notion of uninitialized objects, which means that + objects always have an initial value even if indeterminate. As discussed + on the previous section, this has a drawback because you need additional + information to tell if an object has been effectively initialized. 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 + nil_t—were nil_t + is some stateless POD-can be modeled in modern languages as a discriminated + union of T and nil_t. Discriminated unions are often called variants. + A variant has a current type, which in our case is either + T or nil_t. + Using the Boost.Variant + library, this model can be implemented in terms of boost::variant<T,nil_t>. + There is precedent for a discriminated union as a model for an optional value: + the Haskell Maybe + built-in type constructor. Thus, a discriminated union T+nil_t + serves as a conceptual foundation. +

+

+ A variant<T,nil_t> follows naturally from the traditional + idiom of extending the range of possible values adding an additional sentinel + value with the special meaning of Nothing. However, + this additional Nothing value is largely irrelevant + for our purpose since our goal is to formalize the notion of uninitialized + objects and, while a special extended value can be used to convey that meaning, + it is not strictly necessary in order to do so. +

+

+ The observation made in the last paragraph about the irrelevant nature of + the additional nil_t with + respect to purpose of optional<T> suggests + an alternative model: a container that either has a + value of T or nothing. +

+

+ 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. +

+

+ 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. For instance, these models show the exact + semantics required for a wrapper of optional values: +

+

+ Discriminated-union: +

+
    +
  • +deep-copy semantics: copies of the variant + implies copies of the value. +
  • +
  • +deep-relational semantics: comparisons + between variants matches both current types and values +
  • +
  • + If the variant's current type is T, + it is modeling an initialized optional. +
  • +
  • + If the variant's current type is not T, + it is modeling an uninitialized optional. +
  • +
  • + Testing if the variant's current type is T + models testing if the optional is initialized +
  • +
  • + 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 +
  • +
+

+ Single-element container: +

+
    +
  • +deep-copy semantics: copies of the container + implies copies of the value. +
  • +
  • +deep-relational semantics: comparisons + between containers compare container size and if match, contained value +
  • +
  • + If the container is not empty (contains an object of type T), it is modeling an initialized + optional. +
  • +
  • + If the container is empty, it is modeling an uninitialized + optional. +
  • +
  • + Testing if the container is empty models testing if the optional is initialized +
  • +
  • + Trying to extract a T from + an empty container models the undefined behavior of trying to access the + value of an uninitialized optional +
  • +
+
+
+ +

+ Objects of type optional<T> + are intended to be used in places where objects of type T + would but which might be uninitialized. Hence, optional<T>'s + purpose is to formalize the additional possibly uninitialized state. From + the perspective of this role, optional<T> + can have the same operational semantics of T + plus the additional semantics corresponding to this special state. As such, + optional<T> could + be thought of as a supertype of T. + Of course, we can't do that in C++, so we need to compose the desired semantics + using a different mechanism. Doing it the other way around, that is, making + optional<T> a + subtype 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. +

+

+ We can draw from the purpose of optional<T> + the required basic semantics: +

+
    +
  • +Default Construction: To introduce a formally + uninitialized wrapped object. +
  • +
  • +Direct Value Construction via copy: To + introduce a formally initialized wrapped object whose value is obtained + as a copy of some object. +
  • +
  • +Deep Copy Construction: To obtain a new + yet equivalent wrapped object. +
  • +
  • +Direct Value Assignment (upon initialized): + To assign a value to the wrapped object. +
  • +
  • +Direct Value Assignment (upon uninitialized): + To initialize the wrapped object with a value obtained as a copy of some + object. +
  • +
  • +Assignment (upon initialized): To assign + to the wrapped object the value of another wrapped object. +
  • +
  • +Assignment (upon uninitialized): To initialize + the wrapped object with value of another wrapped object. +
  • +
  • +Deep Relational Operations (when supported by the + type T): To compare wrapped object values taking into account + the presence of uninitialized states. +
  • +
  • +Value access: To unwrap the wrapped object. +
  • +
  • +Initialization state query: To determine + if the object is formally initialized or not. +
  • +
  • +Swap: To exchange wrapped objects. (with + whatever exception safety guarantees are provided by T's + swap). +
  • +
  • +De-initialization: To release the wrapped + object (if any) and leave the wrapper in the uninitialized state. +
  • +
+

+ 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. +

+
+
+ +

+ 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: 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. +

+

+ 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. +

+

+ 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. +

+

+ 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). +

+

+ Also, the presence of the possibly uninitialized state requires additional + operations not provided by T + itself which are supported by a special interface. +

+
+ + Lexically-hinted + Value Access in the presence of possibly untitialized optional objects: The + operators * and -> +
+

+ A relevant feature of a pointer is that it can have a null + pointer value. This is a special 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. +

+

+ This meaning of the null pointer value allowed pointers to became a de + facto 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 refer + to optional (that is, possibly inexistent) objects; particularly as optional + arguments to a function, but also quite often as optional data members. +

+

+ 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: ( + *p = 2 ) + and ( p->foo() ), implicitly + convey the notion of optionality, and this information is tied to the syntax + 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. +

+

+ Such a de facto idiom for referring to optional objects + can be formalized in the form of a concept: the OptionalPointee + concept. This concept captures the syntactic usage of operators *, -> + and conversion to bool to convey + the notion of optionality. +

+

+ However, pointers are good to refer + 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. +

+

+ 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. +

+
+ + Optional<T> + as a model of OptionalPointee +
+

+ 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. +

+
+ + + + + +
[Warning]Warning
+

+

+

+ However, it is particularly important to note that optional<> objects are not pointers. optional<> is not, and does not model, a + pointer. +

+

+

+
+

+ For instance, optional<> + does not have shallow-copy so does not alias: two different optionals never + refer to the same value unless T + itself is a reference (but may have equivalent values). + 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. 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 equal_pointees() + and less_pointees() + instead. +

+
+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/examples.html b/doc/html/boost_optional/examples.html new file mode 100644 index 0000000..7fdb8c8 --- /dev/null +++ b/doc/html/boost_optional/examples.html @@ -0,0 +1,151 @@ + + + +Examples + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ + +
+ +
+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);
+}
+
+
+
+ +
+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!");
+
+
+
+ +
+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 ;
+
+};
+
+
+
+ +
+class ExpensiveCtor { ... } ;
+class Fred
+{
+    Fred() : mLargeVector(10000) {}
+
+    std::vector< optional<ExpensiveCtor> > mLargeVector ;
+} ;
+
+
+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/exception_safety_guarantees.html b/doc/html/boost_optional/exception_safety_guarantees.html new file mode 100644 index 0000000..6b4ab64 --- /dev/null +++ b/doc/html/boost_optional/exception_safety_guarantees.html @@ -0,0 +1,140 @@ + + + +Exception Safety + Guarantees + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Because of the current implementation (see Implementation + Notes), all of the assignment methods: +

+
    +
  • optional<T>::operator= ( optional<T> + const& + )
  • +
  • optional<T>::operator= ( T const& )
  • +
  • template<class U> optional<T>::operator= ( optional<U> + const& + )
  • +
  • template<class InPlaceFactory> optional<T>::operator= ( InPlaceFactory + const& + )
  • +
  • template<class TypedInPlaceFactory> optional<T>::operator= ( TypedInPlaceFactory + const& + )
  • +
  • optional<T>:::reset ( T const&)
  • +
+

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

+

+ On the other hand, the uninitializing methods: +

+
    +
  • optional<T>::operator= ( detail::none_t )
  • +
  • optional<T>::reset()
  • +
+

+ Provide the no-throw guarantee (assuming a no-throw T::~T()) +

+

+ However, since optional<> + 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. +

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

+ + Swap +

+

+ void swap( optional<T>&, + optional<T>& ) has the same exception guarantee as swap(T&,T&) + when both optionals are initialized. If only one of the optionals is initialized, + it gives the same basic exception guarantee as optional<T>::reset( T const& ) (since + optional<T>::reset() doesn't throw). If none of the optionals + is initialized, it has no-throw guarantee since it is a no-op. +

+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/implementation_notes.html b/doc/html/boost_optional/implementation_notes.html new file mode 100644 index 0000000..54af9ab --- /dev/null +++ b/doc/html/boost_optional/implementation_notes.html @@ -0,0 +1,52 @@ + + + +Implementation Notes + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ optional<T> is + currently implemented using a custom aligned storage facility built from alignment_of and type_with_alignment + (both from Type Traits). It uses a separate boolean flag to indicate the initialization + state. Placement new with T's + copy constructor and T's destructor + are explicitly used to initialize,copy and destroy optional values. As a result, + T's default constructor is + effectively by-passed, but the exception guarantees are basic. It is planned + to replace the current implementation with another with stronger exception + safety, such as a future boost::variant. +

+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/in_place_factories.html b/doc/html/boost_optional/in_place_factories.html new file mode 100644 index 0000000..be2ccbf --- /dev/null +++ b/doc/html/boost_optional/in_place_factories.html @@ -0,0 +1,200 @@ + + + +In-Place Factories + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ 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 Copy Constructible, + but also requires the existence of a fully constructed object, often temporary, + just to follow the copy from: +

+
+struct X
+{
+    X ( int, std:::string ) ;
+} ;
+
+class W
+{
+    X wrapped_ ;
+
+    public:
+
+    W ( X const& x ) : wrapped_(x) {}
+} ;
+
+void foo()
+{
+    // Temporary object created.
+    W ( X(123,"hello") ) ;
+}
+
+

+ A solution to this problem is to support direct construction of the contained + object right in the container's storage. In this scheme, the user only needs + to supply the arguments to the constructor to use in the wrapped object construction. +

+
+class W
+{
+    X wrapped_ ;
+
+    public:
+
+    W ( X const& x ) : wrapped_(x) {}
+    W ( int a0, std::string a1) : wrapped_(a0,a1) {}
+} ;
+
+void foo()
+{
+    // Wrapped object constructed in-place
+    // No temporary created.
+    W (123,"hello") ;
+}
+
+

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

+

+ The solution presented in this library is the family of InPlaceFactories + and TypedInPlaceFactories. 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. +

+

+ For example, one member of this family looks like: +

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

+ A wrapper class aware of this can use it as: +

+
+class W
+{
+    X wrapped_ ;
+
+    public:
+
+    W ( X const& x ) : wrapped_(x) {}
+    W ( TypedInPlaceFactory2 const& fac ) { fac.construct(&wrapped_) ; }
+} ;
+
+void foo()
+{
+    // Wrapped object constructed in-place via a TypedInPlaceFactory.
+    // No temporary created.
+    W ( TypedInPlaceFactory2<X,int,std::string&rt(123,"hello")) ;
+}
+
+

+ The factories are divided in two groups: +

+
    +
  • +TypedInPlaceFactories: those which + take the target type as a primary template parameter. +
  • +
  • +InPlaceFactories: those with a template + construct(void*) member + function taking the target type. +
  • +
+

+ Within each group, all the family members differ only in the number of parameters + allowed. +

+

+ This library provides an overloaded set of helper template functions to construct + these factories without requiring unnecessary template parameters: +

+
+template<class A0,...,class AN>
+InPlaceFactoryN <A0,...,AN> in_place ( A0 const& a0, ..., AN const& aN) ;
+
+template<class T,class A0,...,class AN>
+TypedInPlaceFactoryN <T,A0,...,AN> in_place ( T const& a0, A0 const& a0, ..., AN const& aN) ;
+
+

+ In-place factories can be used generically by the wrapper and user as follows: +

+
+class W
+{
+    X wrapped_ ;
+
+    public:
+
+    W ( X const& x ) : wrapped_(x) {}
+
+    template< class InPlaceFactory >
+    W ( InPlaceFactory const& fac ) { fac.template <X>construct(&wrapped_) ; }
+
+} ;
+
+void foo()
+{
+    // Wrapped object constructed in-place via a InPlaceFactory.
+    // No temporary created.
+    W ( in_place(123,"hello") ) ;
+}
+
+

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

+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/optional_references.html b/doc/html/boost_optional/optional_references.html new file mode 100644 index 0000000..396dff0 --- /dev/null +++ b/doc/html/boost_optional/optional_references.html @@ -0,0 +1,82 @@ + + + +Optional references + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ This library allows the template parameter T + to be of reference type: T&, and to some extent, T + const&. +

+

+ However, since references are not real objects some restrictions apply and + some operations are not available in this case: +

+
    +
  • + Converting constructors +
  • +
  • + Converting assignment +
  • +
  • + InPlace construction +
  • +
  • + InPlace assignment +
  • +
  • + Value-access via pointer +
  • +
+

+ 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: +

+
    +
  • + Copies of optional<T&> + will copy the references but all these references will nonetheless reefer + to the same object. +
  • +
  • + Value-access will actually provide access to the referenced object rather + than the reference itself. +
  • +
+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/rebinding_semantics_for_assignment_of_optional_references.html b/doc/html/boost_optional/rebinding_semantics_for_assignment_of_optional_references.html new file mode 100644 index 0000000..8906812 --- /dev/null +++ b/doc/html/boost_optional/rebinding_semantics_for_assignment_of_optional_references.html @@ -0,0 +1,151 @@ + + + +Rebinding + semantics for assignment of optional references + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ If you assign to an uninitialized optional<T&> + the effect is to bind (for the first time) to the object. Clearly, there is + no other choice. +

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

+ 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. +

+
+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'
+
+

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

+
+int a = 1 ;
+int b = 2 ;
+int& ra = a ;
+int& rb = b ;
+optional<int&> ora(ra) ;
+optional<int&> orb(rb) ;
+ora = orb ; // 'ora' is rebound to 'b'
+*ora = 3 ; // Changes value of 'b' (not 'a')
+assert(a==1); 
+assert(b==3); 
+
+

+ + Rationale +

+

+ Rebinding semantics for the assignment of initialized + optional references has been + chosen to provide consistency among initialization states + even at the expense of lack of consistency with the semantics of bare C++ references. + 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. +

+

+ Imagine optional<T&> + forwarding assignment to the referenced object (thus changing the referenced + object value but not rebinding), and consider the following code: +

+
+optional<int&> a = get();
+int x = 1 ;
+int& rx = x ;
+optional<int&> b(rx);
+a = b ;
+
+

+ What does the assignment do? +

+

+ If a is uninitialized, + the answer is clear: it binds to x + (we now have another reference to x). + But what if a is already initialized? + it would change the value of the referenced object (whatever that is); which + is inconsistent with the other possible case. +

+

+ 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. +

+

+ That is, you would have to discriminate in order to be consistency. +

+

+ 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 uninitialized 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. + In such scenario, you can assign the value itself directly, as in: +

+
+assert(!!opt);
+*opt=value;
+
+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/synopsis.html b/doc/html/boost_optional/synopsis.html new file mode 100644 index 0000000..198750e --- /dev/null +++ b/doc/html/boost_optional/synopsis.html @@ -0,0 +1,147 @@ + + + +Synopsis + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +
+namespace boost {
+
+template<class T>
+class optional
+{
+    public :
+
+    // (If T is of reference type, the parameters and results by reference are by value)
+
+    optional () ; R
+
+    optional ( none_t ) ; R
+
+    optional ( T const& v ) ; R
+
+    // [new in 1.34]
+    optional ( bool condition, T const& v ) ; R 
+
+    optional ( optional const& rhs ) ; R
+
+    template<class U> explicit optional ( optional<U> const& rhs ) ; R
+
+    template<class InPlaceFactory> explicit optional ( InPlaceFactory const& f ) ; R
+
+    template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ; R
+
+    optional& operator = ( none_t ) ; 
+
+    optional& operator = ( T const& v ) ; R
+
+    optional& operator = ( optional const& rhs ) ; R
+
+    template<class U> optional& operator = ( optional<U> const& rhs ) ; R
+
+    template<class InPlaceFactory> optional& operator = ( InPlaceFactory const& f ) ; 
+
+    template<class TypedInPlaceFactory> optional& operator = ( TypedInPlaceFactory const& f ) ; 
+
+    T const& get() const ; R
+    T&       get() ; R
+
+    // [new in 1.34]
+    T const& get_value_or( T const& default ) const ; R 
+
+    T const* operator ->() const ; R
+    T*       operator ->() ; R
+
+    T const& operator *() const ; R
+    T&       operator *() ; R
+
+    T const* get_ptr() const ; R
+    T*       get_ptr() ; R
+
+    operator unspecified-bool-type() const ; R
+
+    bool operator!() const ; R
+
+    // deprecated methods
+
+    // (deprecated)
+    void reset() ; R
+
+    // (deprecated)
+    void reset ( T const& ) ; R
+
+    // (deprecated)
+    bool is_initialized() const ; R
+
+};
+
+template<class T> inline bool operator == ( optional<T> const& x, optional<T> const& y ) ; R
+
+template<class T> inline bool operator != ( optional<T> const& x, optional<T> const& y ) ; R
+
+template<class T> inline bool operator <  ( optional<T> const& x, optional<T> const& y ) ; R
+
+template<class T> inline bool operator >  ( optional<T> const& x, optional<T> const& y ) ; R
+
+template<class T> inline bool operator <= ( optional<T> const& x, optional<T> const& y ) ; R
+
+template<class T> inline bool operator >= ( optional<T> const& x, optional<T> const& y ) ; R
+
+// [new in 1.34]
+template<class T> inline optional<T> make_optional ( T const& v ) ; R
+
+// [new in 1.34]
+template<class T> inline optional<T> make_optional ( bool condition, T const& v ) ; R
+
+// [new in 1.34]
+template<class T> inline T const& get_optional_value_or ( optional<T> const& opt, T const& default ) ; R 
+
+template<class T> inline T const& get ( optional<T> const& opt ) ; R
+
+template<class T> inline T& get ( optional<T> & opt ) ; R
+
+template<class T> inline T const* get ( optional<T> const* opt ) ; R
+
+template<class T> inline T* get ( optional<T>* opt ) ; R
+
+template<class T> inline T const* get_pointer ( optional<T> const& opt ) ; R
+
+template<class T> inline T* get_pointer ( optional<T> & opt ) ; R
+
+template<class T> inline void swap( optional<T>& x, optional<T>& y ) ; R
+
+} // namespace boost
+
+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/type_requirements.html b/doc/html/boost_optional/type_requirements.html new file mode 100644 index 0000000..8da1a86 --- /dev/null +++ b/doc/html/boost_optional/type_requirements.html @@ -0,0 +1,50 @@ + + + +Type requirements + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ In general, T must be Copy Constructible and + have a no-throw destructor. The copy-constructible requirement is not needed + if InPlaceFactories are used. +

+

+ T is + not required to be Default + Constructible. +

+
+ + + +
Copyright © 2003 -2007 Fernando Luis Cacciola Carballal
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boostbook.css b/doc/html/boostbook.css new file mode 100755 index 0000000..e5d7bb5 --- /dev/null +++ b/doc/html/boostbook.css @@ -0,0 +1,582 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + http://spirit.sourceforge.net/ + + 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) +=============================================================================*/ + +/*============================================================================= + Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= + Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= + Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 10pt; + } + + pre.synopsis + { + font-size: 10pt; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 10pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= + Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font: 140% } + h2 { font: bold 140% } + h3 { font: bold 130% } + h4 { font: bold 120% } + h5 { font: italic 110% } + h6 { font: italic 100% } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 120% } + h5 tt.computeroutput { font-size: 110% } + h6 tt.computeroutput { font-size: 100% } + +/*============================================================================= + Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= + Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= + Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= + Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= + Table of contents +=============================================================================*/ + + .toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 10pt; + line-height: 1.15; + } + + .toc-main + { + text-align: center; + margin: 3pc 16% 3pc 16%; + padding: 3pc 1pc 3pc 1pc; + line-height: 0.1; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + +/*============================================================================= + Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 120%; + } + +/*============================================================================= + Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + div.sidebar + { + font-size: 10pt; + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + div.sidebar img + { + padding: 1pt; + } + + + +/*============================================================================= + Callouts +=============================================================================*/ + .line_callout_bug img + { + float: left; + position:relative; + left: 4px; + top: -12px; + clear: left; + margin-left:-22px; + } + + .callout_bug img + { + } + + + +/*============================================================================= + Variable Lists +=============================================================================*/ + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= + Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= + Colors +=============================================================================*/ + + @media screen + { + /* Links */ + a + { + color: #0C7445; + } + + a:visited + { + color: #663974; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #E8FBE9; } + .dk_grey_bkd { background-color: #A0DAAC; } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + div.sidebar + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + /* Table of contents */ + .toc + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + /* Table of contents */ + .toc-main + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + background-color: #FAFFFB; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #E3F9E4; + border: 1px solid #DCDCDC; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + background-color: #FAFFFB; + } + + .programlisting, + .screen + { + border: 1px solid gray; + background-color: #FAFFFB; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + /* Table of contents */ + .toc-main + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + .informaltable table, + .table table + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + border-collapse: collapse; + background-color: #FAFFFB; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + background-color: #FAFFFB; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid #DCDCDC; + background-color: #FAFFFB; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } diff --git a/doc/html/images/callouts/1.png b/doc/html/images/callouts/1.png new file mode 100644 index 0000000..6003ad3 Binary files /dev/null and b/doc/html/images/callouts/1.png differ diff --git a/doc/html/images/callouts/10.png b/doc/html/images/callouts/10.png new file mode 100644 index 0000000..0426f51 Binary files /dev/null and b/doc/html/images/callouts/10.png differ diff --git a/doc/html/images/callouts/11.png b/doc/html/images/callouts/11.png new file mode 100644 index 0000000..821afc4 Binary files /dev/null and b/doc/html/images/callouts/11.png differ diff --git a/doc/html/images/callouts/12.png b/doc/html/images/callouts/12.png new file mode 100644 index 0000000..7cec727 Binary files /dev/null and b/doc/html/images/callouts/12.png differ diff --git a/doc/html/images/callouts/13.png b/doc/html/images/callouts/13.png new file mode 100644 index 0000000..5b41e02 Binary files /dev/null and b/doc/html/images/callouts/13.png differ diff --git a/doc/html/images/callouts/14.png b/doc/html/images/callouts/14.png new file mode 100644 index 0000000..de5bdbd Binary files /dev/null and b/doc/html/images/callouts/14.png differ diff --git a/doc/html/images/callouts/15.png b/doc/html/images/callouts/15.png new file mode 100644 index 0000000..3fd6ac3 Binary files /dev/null and b/doc/html/images/callouts/15.png differ diff --git a/doc/html/images/callouts/2.png b/doc/html/images/callouts/2.png new file mode 100644 index 0000000..f7c1578 Binary files /dev/null and b/doc/html/images/callouts/2.png differ diff --git a/doc/html/images/callouts/3.png b/doc/html/images/callouts/3.png new file mode 100644 index 0000000..3ff0a93 Binary files /dev/null and b/doc/html/images/callouts/3.png differ diff --git a/doc/html/images/callouts/4.png b/doc/html/images/callouts/4.png new file mode 100644 index 0000000..6aa29fc Binary files /dev/null and b/doc/html/images/callouts/4.png differ diff --git a/doc/html/images/callouts/5.png b/doc/html/images/callouts/5.png new file mode 100644 index 0000000..36e7858 Binary files /dev/null and b/doc/html/images/callouts/5.png differ diff --git a/doc/html/images/callouts/6.png b/doc/html/images/callouts/6.png new file mode 100644 index 0000000..c943676 Binary files /dev/null and b/doc/html/images/callouts/6.png differ diff --git a/doc/html/images/callouts/7.png b/doc/html/images/callouts/7.png new file mode 100644 index 0000000..20940de Binary files /dev/null and b/doc/html/images/callouts/7.png differ diff --git a/doc/html/images/callouts/8.png b/doc/html/images/callouts/8.png new file mode 100644 index 0000000..d8e34d4 Binary files /dev/null and b/doc/html/images/callouts/8.png differ diff --git a/doc/html/images/callouts/9.png b/doc/html/images/callouts/9.png new file mode 100644 index 0000000..abe6360 Binary files /dev/null and b/doc/html/images/callouts/9.png differ diff --git a/doc/html/images/callouts/R.png b/doc/html/images/callouts/R.png new file mode 100644 index 0000000..bee36a1 Binary files /dev/null and b/doc/html/images/callouts/R.png differ diff --git a/doc/html/images/caution.png b/doc/html/images/caution.png new file mode 100755 index 0000000..3c3b859 Binary files /dev/null and b/doc/html/images/caution.png differ diff --git a/doc/html/images/home.png b/doc/html/images/home.png new file mode 100755 index 0000000..f2047b8 Binary files /dev/null and b/doc/html/images/home.png differ diff --git a/doc/html/images/important.png b/doc/html/images/important.png new file mode 100755 index 0000000..54b4846 Binary files /dev/null and b/doc/html/images/important.png differ diff --git a/doc/html/images/next.png b/doc/html/images/next.png new file mode 100755 index 0000000..f3a1221 Binary files /dev/null and b/doc/html/images/next.png differ diff --git a/doc/html/images/note.png b/doc/html/images/note.png new file mode 100755 index 0000000..c3bebc7 Binary files /dev/null and b/doc/html/images/note.png differ diff --git a/doc/html/images/prev.png b/doc/html/images/prev.png new file mode 100755 index 0000000..f7f0361 Binary files /dev/null and b/doc/html/images/prev.png differ diff --git a/doc/html/images/space.png b/doc/html/images/space.png new file mode 100644 index 0000000..8e6dcfb Binary files /dev/null and b/doc/html/images/space.png differ diff --git a/doc/html/images/tip.png b/doc/html/images/tip.png new file mode 100755 index 0000000..d96e9bd Binary files /dev/null and b/doc/html/images/tip.png differ diff --git a/doc/html/images/up.png b/doc/html/images/up.png new file mode 100755 index 0000000..ef43407 Binary files /dev/null and b/doc/html/images/up.png differ diff --git a/doc/html/images/warning.png b/doc/html/images/warning.png new file mode 100755 index 0000000..51a30f7 Binary files /dev/null and b/doc/html/images/warning.png differ diff --git a/doc/html/index.html b/doc/html/index.html new file mode 100644 index 0000000..298875d --- /dev/null +++ b/doc/html/index.html @@ -0,0 +1,168 @@ + + + +Chapter 1. Boost.Optional + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
Next
+
+
+

+Chapter 1. Boost.Optional

+

+Fernando Luis Cacciola Carballal +

+
+
+

+ Distributed under 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) +

+
+
+ +
+ +

+ Consider these functions which should return a value but which might not have + a value to return: +

+
    +
  • + (A) double sqrt(double n + ); +
  • +
  • + (B) char get_async_input(); +
  • +
  • + (C) point polygon::get_any_point_effectively_inside(); +
  • +
+

+ There are different approaches to the issue of not having a value to return. +

+

+ A typical approach is to consider the existence of a valid return value as + a postcondition, so that if the function cannot compute the value to return, + it has either undefined behavior (and can use assert in a debug build) or uses + a runtime check and throws an exception if the postcondition is violated. This + is a reasonable choice for example, for function (A), because the lack of a + proper return value is directly related to an invalid parameter (out of domain + argument), so it is appropriate to require the callee to supply only parameters + in a valid domain for execution to continue normally. +

+

+ However, function (B), because of its asynchronous nature, does not fail just + because it can't find a value to return; so it is incorrect to consider such + a situation an error and assert or throw an exception. This function must return, + and somehow, must tell the callee that it is not returning a meaningful value. +

+

+ A similar situation occurs with function (C): it is conceptually an error to + ask a null-area polygon to return a point inside itself, + but in many applications, it is just impractical for performance reasons to + treat this as an error (because detecting that the polygon has no area might + be too expensive to be required to be tested previously), and either an arbitrary + point (typically at infinity) is returned, or some efficient way to tell the + callee that there is no such point is used. +

+

+ There are various mechanisms to let functions communicate that the returned + value is not valid. One such mechanism, which is quite common since it has + zero or negligible overhead, is to use a special value which is reserved to + communicate this. Classical examples of such special values are EOF, string::npos, points + at infinity, etc... +

+

+ When those values exist, i.e. the return type can hold all meaningful values + plus the signal value, this mechanism + is quite appropriate and well known. Unfortunately, there are cases when such + values do not exist. In these cases, the usual alternative is either to use + a wider type, such as int in place + of char; or a compound type, such + as std::pair<point,bool>. +

+

+ Returning a std::pair<T,bool>, thus attaching a boolean flag to the result + which indicates if the result is meaningful, has the advantage that can be + turned into a consistent idiom since the first element of the pair can be whatever + the function would conceptually return. For example, the last two functions + could have the following interface: +

+
+std::pair<char,bool> get_async_input();
+std::pair<point,bool> polygon::get_any_point_effectively_inside();
+
+

+ These functions use a consistent interface for dealing with possibly inexistent + results: +

+
+std::pair<point,bool> p = poly.get_any_point_effectively_inside();
+if ( p.second )
+    flood_fill(p.first);
+
+

+ However, not only is this quite a burden syntactically, it is also error prone + since the user can easily use the function result (first element of the pair) + without ever checking if it has a valid value. +

+

+ Clearly, we need a better idiom. +

+
+

+

+

+

+

+

+

+

+
+ + + +

Last revised: May 29, 2007 at 06:31:03 GMT

+
+
Next
+ + diff --git a/doc/implementation_notes.qbk b/doc/implementation_notes.qbk new file mode 100644 index 0000000..519b3ee --- /dev/null +++ b/doc/implementation_notes.qbk @@ -0,0 +1,28 @@ +[/ + Boost.Optional + + Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal + + Distributed under 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) +] + + + +[#optional_implementation_notes] + +[section Implementation Notes] + +`optional` is currently implemented using a custom aligned storage facility +built from `alignment_of` and `type_with_alignment` (both from Type Traits). It +uses a separate boolean flag to indicate the initialization state. +Placement new with `T`'s copy constructor and `T`'s destructor are explicitly used +to initialize,copy and destroy optional values. +As a result, `T`'s default constructor is effectively by-passed, but the exception +guarantees are basic. +It is planned to replace the current implementation with another with stronger +exception safety, such as a future `boost::variant`. + +[endsect] + diff --git a/doc/optional.qbk b/doc/optional.qbk new file mode 100644 index 0000000..388f686 --- /dev/null +++ b/doc/optional.qbk @@ -0,0 +1,131 @@ +[library Boost.Optional + [quickbook 1.4] + [authors [Cacciola Carballal, Fernando Luis]] + [copyright 2003-2007 Fernando Luis Cacciola Carballal] + [category miscellaneous] + [id optional] + [dirname optional] + [purpose + Discriminated-union wrapper for optional values + ] + [source-mode c++] + [license +Distributed under 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]) + ] +] + +[/ Macros will be used for links so we have a central place to change them ] + + +[/ Cited Boost resources ] + +[def __BOOST_VARIANT__ [@../../../variant/index.html Boost.Variant]] +[def __BOOST_TRIBOOL__ [@../../../tribool/index.html boost::tribool]] + +[def __OPTIONAL_POINTEE__ [@../../../utility/OptionalPointee.html OptionalPointee]] +[def __COPY_CONSTRUCTIBLE__ [@../../../utility/CopyConstructible.html Copy Constructible]] +[def __FUNCTION_EQUAL_POINTEES__ [@../../../utility/OptionalPointee.html#equal `equal_pointees()`]] +[def __FUNCTION_LESS_POINTEES__ [@../../../utility/OptionalPointee.html#less `less_pointees()`]] + +[def __IN_PLACE_FACTORY_HPP__ [@../../../../boost/utility/in_place_factory.hpp in_place_factory.hpp]] +[def __TYPED_IN_PLACE_FACTORY_HPP__ [@../../../../boost/utility/typed_in_place_factory.hpp typed_in_place_factory.hpp]] + +[/ Other web resources ] + +[def __HASKELL__ [@http://www.haskell.org/ Haskell]] +[def __SGI_DEFAULT_CONSTRUCTIBLE__ [@http://www.sgi.com/tech/stl/DefaultConstructible.html Default Constructible]] + + +[/ Icons ] + +[def __NOTE__ [$images/note.png]] +[def __ALERT__ [$images/caution.png]] +[def __DETAIL__ [$images/note.png]] +[def __TIP__ [$images/tip.png]] +[def __QUESTION_MARK__ [$images/question.png]] +[def __SPACE__ [$images/space.png]] +[def __GO_TO__ [$images/callouts/R.png]] + + +[section Motivation] + +Consider these functions which should return a value but which might not have +a value to return: + +* (A) `double sqrt(double n );` +* (B) `char get_async_input();` +* (C) `point polygon::get_any_point_effectively_inside();` + +There are different approaches to the issue of not having a value to return. + +A typical approach is to consider the existence of a valid return value as a +postcondition, so that if the function cannot compute the value to return, it +has either undefined behavior (and can use assert in a debug build) or uses a +runtime check and throws an exception if the postcondition is violated. This +is a reasonable choice for example, for function (A), because the lack of a +proper return value is directly related to an invalid parameter (out of domain +argument), so it is appropriate to require the callee to supply only parameters +in a valid domain for execution to continue normally. + +However, function (B), because of its asynchronous nature, does not fail just +because it can't find a value to return; so it is incorrect to consider such +a situation an error and assert or throw an exception. This function must +return, and somehow, must tell the callee that it is not returning a meaningful +value. + +A similar situation occurs with function (C): it is conceptually an error to +ask a ['null-area] polygon to return a point inside itself, but in many +applications, it is just impractical for performance reasons to treat this as +an error (because detecting that the polygon has no area might be too expensive +to be required to be tested previously), and either an arbitrary point +(typically at infinity) is returned, or some efficient way to tell the callee +that there is no such point is used. + +There are various mechanisms to let functions communicate that the returned +value is not valid. One such mechanism, which is quite common since it has +zero or negligible overhead, is to use a special value which is reserved to +communicate this. Classical examples of such special values are `EOF`, +`string::npos`, points at infinity, etc... + +When those values exist, i.e. the return type can hold all meaningful values +['plus] the ['signal] value, this mechanism is quite appropriate and well known. +Unfortunately, there are cases when such values do not exist. In these cases, +the usual alternative is either to use a wider type, such as `int` in place of +`char`; or a compound type, such as `std::pair`. + +Returning a `std::pair`, thus attaching a boolean flag to the result +which indicates if the result is meaningful, has the advantage that can be +turned into a consistent idiom since the first element of the pair can be +whatever the function would conceptually return. For example, the last two +functions could have the following interface: + + std::pair get_async_input(); + std::pair polygon::get_any_point_effectively_inside(); + +These functions use a consistent interface for dealing with possibly inexistent +results: + + std::pair p = poly.get_any_point_effectively_inside(); + if ( p.second ) + flood_fill(p.first); + +However, not only is this quite a burden syntactically, it is also error prone +since the user can easily use the function result (first element of the pair) +without ever checking if it has a valid value. + +Clearly, we need a better idiom. + +[endsect] + + +[include development.qbk] +[include reference.qbk] +[include examples.qbk] +[include special_cases.qbk] +[include implementation_notes.qbk] +[include dependencies.qbk] +[include acknowledgments.qbk] + + diff --git a/doc/reference.qbk b/doc/reference.qbk new file mode 100644 index 0000000..73993b3 --- /dev/null +++ b/doc/reference.qbk @@ -0,0 +1,880 @@ +[/ + Boost.Optional + + Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal + + Distributed under 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) +] + + +[section Synopsis] + + namespace boost { + + template + class optional + { + public : + + // (If T is of reference type, the parameters and results by reference are by value) + + optional () ; ``[link reference_optional_constructor __GO_TO__]`` + + optional ( none_t ) ; ``[link reference_optional_constructor_none_t __GO_TO__]`` + + optional ( T const& v ) ; ``[link reference_optional_constructor_value __GO_TO__]`` + + // [new in 1.34] + optional ( bool condition, T const& v ) ; ``[link reference_optional_constructor_bool_value __GO_TO__]`` + + optional ( optional const& rhs ) ; ``[link reference_optional_constructor_optional __GO_TO__]`` + + template explicit optional ( optional const& rhs ) ; ``[link reference_optional_constructor_other_optional __GO_TO__]`` + + template explicit optional ( InPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]`` + + template explicit optional ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]`` + + optional& operator = ( none_t ) ; ``[/[link reference_optional_operator_equal_none_t __GO_TO__]]`` + + optional& operator = ( T const& v ) ; ``[link reference_optional_operator_equal_value __GO_TO__]`` + + optional& operator = ( optional const& rhs ) ; ``[link reference_optional_operator_equal_optional __GO_TO__]`` + + template optional& operator = ( optional const& rhs ) ; ``[link reference_optional_operator_equal_other_optional __GO_TO__]`` + + template optional& operator = ( InPlaceFactory const& f ) ; ``[/[link reference_optional_operator_equal_factory __GO_TO__]]`` + + template optional& operator = ( TypedInPlaceFactory const& f ) ; ``[/[link reference_optional_operator_equal_factory __GO_TO__]]`` + + T const& get() const ; ``[link reference_optional_get __GO_TO__]`` + T& get() ; ``[link reference_optional_get __GO_TO__]`` + + // [new in 1.34] + T const& get_value_or( T const& default ) const ; ``[link reference_optional_get_value_or_value __GO_TO__]`` + + T const* operator ->() const ; ``[link reference_optional_operator_arrow __GO_TO__]`` + T* operator ->() ; ``[link reference_optional_operator_arrow __GO_TO__]`` + + T const& operator *() const ; ``[link reference_optional_get __GO_TO__]`` + T& operator *() ; ``[link reference_optional_get __GO_TO__]`` + + T const* get_ptr() const ; ``[link reference_optional_get_ptr __GO_TO__]`` + T* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]`` + + operator unspecified-bool-type() const ; ``[link reference_optional_operator_bool __GO_TO__]`` + + bool operator!() const ; ``[link reference_optional_operator_not __GO_TO__]`` + + // deprecated methods + + // (deprecated) + void reset() ; ``[link reference_optional_reset __GO_TO__]`` + + // (deprecated) + void reset ( T const& ) ; ``[link reference_optional_reset_value __GO_TO__]`` + + // (deprecated) + bool is_initialized() const ; ``[link reference_optional_is_initialized __GO_TO__]`` + + }; + + template inline bool operator == ( optional const& x, optional const& y ) ; ``[link reference_operator_compare_equal_optional_optional __GO_TO__]`` + + template inline bool operator != ( optional const& x, optional const& y ) ; ``[link reference_operator_compare_not_equal_optional_optional __GO_TO__]`` + + template inline bool operator < ( optional const& x, optional const& y ) ; ``[link reference_operator_compare_less_optional_optional __GO_TO__]`` + + template inline bool operator > ( optional const& x, optional const& y ) ; ``[link reference_operator_compare_greater_optional_optional __GO_TO__]`` + + template inline bool operator <= ( optional const& x, optional const& y ) ; ``[link reference_operator_compare_less_or_equal_optional_optional __GO_TO__]`` + + template inline bool operator >= ( optional const& x, optional const& y ) ; ``[link reference_operator_compare_greater_or_equal_optional_optional __GO_TO__]`` + + // [new in 1.34] + template inline optional make_optional ( T const& v ) ; ``[link reference_make_optional_value __GO_TO__]`` + + // [new in 1.34] + template inline optional make_optional ( bool condition, T const& v ) ; ``[link reference_make_optional_bool_value __GO_TO__]`` + + // [new in 1.34] + template inline T const& get_optional_value_or ( optional const& opt, T const& default ) ; ``[link reference_optional_get_value_or_value __GO_TO__]`` + + template inline T const& get ( optional const& opt ) ; ``[link reference_optional_get __GO_TO__]`` + + template inline T& get ( optional & opt ) ; ``[link reference_optional_get __GO_TO__]`` + + template inline T const* get ( optional const* opt ) ; ``[link reference_optional_get __GO_TO__]`` + + template inline T* get ( optional* opt ) ; ``[link reference_optional_get __GO_TO__]`` + + template inline T const* get_pointer ( optional const& opt ) ; ``[link reference_optional_get_ptr __GO_TO__]`` + + template inline T* get_pointer ( optional & opt ) ; ``[link reference_optional_get_ptr __GO_TO__]`` + + template inline void swap( optional& x, optional& y ) ; ``[link reference_swap_optional_optional __GO_TO__]`` + + } // namespace boost + + +[endsect] + +[section Detailed Semantics] + +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: +* If the entry reads: `optional`, the description +corresponds only to the case where `T` is not of reference type. +* If the entry reads: `optional`, the description corresponds only to +the case where `T` is of reference type. +* If the entry reads: `optional`, the description is the same for both +cases. + +[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. +] + +__SPACE__ + +[heading optional class member functions] + +__SPACE__ + +[#reference_optional_constructor] + +[: `optional::optional();`] + +* [*Effect:] Default-Constructs an `optional`. +* [*Postconditions:] `*this` is [_uninitialized]. +* [*Throws:] Nothing. +* Notes: T's default constructor [_is not] called. +* [*Example:] +`` +optional def ; +assert ( !def ) ; +`` + +__SPACE__ + +[#reference_optional_constructor_none_t] + +[: `optional::optional( none_t );`] + +* [*Effect:] Constructs an `optional` uninitialized. +* [*Postconditions:] `*this` is [_uninitialized]. +* [*Throws:] Nothing. +* [*Notes:] `T`'s default constructor [_is not] called. The expression +`boost::none` denotes an instance of `boost::none_t` that can be used as +the parameter. +* [*Example:] +`` +#include +optional n(none) ; +assert ( !n ) ; +`` + +__SPACE__ + +[#reference_optional_constructor_value] + +[: `optional::optional( T const& v )`] + +* [*Effect:] Directly-Constructs an `optional`. +* [*Postconditions:] `*this` is [_initialized] and its value is a['copy] +of `v`. +* [*Throws:] Whatever `T::T( T const& )` throws. +* [*Notes: ] `T::T( T const& )` is called. +* [*Exception Safety:] Exceptions can only be thrown during +`T::T( T const& );` in that case, this constructor has no effect. +* [*Example:] +`` +T v; +optional opt(v); +assert ( *opt == v ) ; +`` + +__SPACE__ + +[: `optional::optional( T& ref )`] + +* [*Effect:] Directly-Constructs an `optional`. +* [*Postconditions:] `*this` is [_initialized] and its value is an instance +of an internal type wrapping the reference `ref`. +* [*Throws:] Nothing. +* [*Example:] +`` +T v; +T& vref = v ; +optional opt(vref); +assert ( *opt == v ) ; +++ v ; // mutate referee +assert (*opt == v); +`` + +__SPACE__ + +[#reference_optional_constructor_bool_value] + +[: `optional::optional( bool condition, T const& v ) ;` ] +[: `optional ::optional( bool condition, T& v ) ;` ] + +* If condition is true, same as: + +[: `optional::optional( T const& v )`] +[: `optional ::optional( T& v )`] + +* otherwise, same as: + +[: `optional::optional()`] +[: `optional ::optional()`] + +__SPACE__ + +[#reference_optional_constructor_optional] + +[: `optional::optional( optional const& rhs );`] + +* [*Effect:] Copy-Constructs an `optional`. +* [*Postconditions:] If rhs is initialized, `*this` is initialized and +its value is a ['copy] of the value of `rhs`; else `*this` is uninitialized. +* [*Throws:] Whatever `T::T( T const& )` throws. +* [*Notes:] If rhs is initialized, `T::T(T const& )` is called. +* [*Exception Safety:] Exceptions can only be thrown during +`T::T( T const& );` in that case, this constructor has no effect. +* [*Example:] +`` +optional uninit ; +assert (!uninit); + +optional uinit2 ( uninit ) ; +assert ( uninit2 == uninit ); + +optional init( T(2) ); +assert ( *init == T(2) ) ; + +optional init2 ( init ) ; +assert ( init2 == init ) ; +`` + +__SPACE__ + +[: `optional::optional( optional const& rhs );`] + +* [*Effect:] Copy-Constructs an `optional`. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its +value is another reference to the same object referenced by `*rhs`; else +`*this` is uninitialized. +* [*Throws:] Nothing. +* [*Notes:] If `rhs` is initialized, both `*this` and `*rhs` will reefer to the +same object (they alias). +* [*Example:] +`` +optional uninit ; +assert (!uninit); + +optional uinit2 ( uninit ) ; +assert ( uninit2 == uninit ); + +T v = 2 ; T& ref = v ; +optional init(ref); +assert ( *init == v ) ; + +optional init2 ( init ) ; +assert ( *init2 == v ) ; + +v = 3 ; + +assert ( *init == 3 ) ; +assert ( *init2 == 3 ) ; +`` + +__SPACE__ + +[#reference_optional_constructor_other_optional] + +[: `template explicit optional::optional( optional const& rhs );`] + +* [*Effect:] Copy-Constructs an `optional`. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its +value is a ['copy] of the value of rhs converted to type `T`; else `*this` is +uninitialized. +* [*Throws:] Whatever `T::T( U const& )` throws. +* [*Notes: ] `T::T( U const& )` is called if `rhs` is initialized, which requires a +valid conversion from `U` to `T`. +* [*Exception Safety:] Exceptions can only be thrown during `T::T( U const& );` +in that case, this constructor has no effect. +* [*Example:] +`` +optional x(123.4); +assert ( *x == 123.4 ) ; + +optional y(x) ; +assert( *y == 123 ) ; +`` + +__SPACE__ + +[#reference_optional_constructor_factory] + +[: `template explicit optional::optional( InPlaceFactory const& f );`] +[: `template explicit optional::optional( TypedInPlaceFactory const& f );`] + +* [*Effect:] Constructs an `optional` with a value of `T` obtained from the +factory. +* [*Postconditions: ] `*this` is [_initialized] and its value is ['directly given] +from the factory `f` (i.e., the value [_is not copied]). +* [*Throws:] Whatever the `T` constructor called by the factory throws. +* [*Notes:] See [link optional_in_place_factories In-Place Factories] +* [*Exception Safety:] Exceptions can only be thrown during the call to +the `T` constructor used by the factory; in that case, this constructor has +no effect. +* [*Example:] +`` +class C { C ( char, double, std::string ) ; } ; + +C v('A',123.4,"hello"); + +optional x( in_place ('A', 123.4, "hello") ); // InPlaceFactory used +optional y( in_place('A', 123.4, "hello") ); // TypedInPlaceFactory used + +assert ( *x == v ) ; +assert ( *y == v ) ; +`` + +__SPACE__ + +[#reference_optional_operator_equal_value] + +[: `optional& optional::operator= ( T const& rhs ) ;`] + +* [*Effect:] Assigns the value `rhs` to an `optional`. +* [*Postconditions: ] `*this` is initialized and its value is a ['copy] of `rhs`. +* [*Throws:] Whatever `T::operator=( T const& )` or `T::T(T const&)` throws. +* [*Notes:] If `*this` was initialized, `T`'s assignment operator is used, +otherwise, its copy-constructor is used. +* [*Exception Safety:] In the event of an exception, the initialization +state of `*this` is unchanged and its value unspecified as far as `optional` +is concerned (it is up to `T`'s `operator=()`). If `*this` is initially +uninitialized and `T`'s ['copy constructor] fails, `*this` is left properly +uninitialized. +* [*Example:] +`` +T x; +optional def ; +optional opt(x) ; + +T y; +def = y ; +assert ( *def == y ) ; +opt = y ; +assert ( *opt == y ) ; +`` + +__SPACE__ + +[: `optional& optional::operator= ( T& const& rhs ) ;`] + +* [*Effect:] (Re)binds thee wrapped reference. +* [*Postconditions: ] `*this` is initialized and it references the same +object referenced by `rhs`. +* [*Notes:] If `*this` was initialized, is is ['rebound] to the new object. +See [link optional_refassign here] for details on this behavior. +* [*Example:] +`` +int a = 1 ; +int b = 2 ; +T& ra = a ; +T& rb = b ; +optional def ; +optional 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 ) ; +`` + +__SPACE__ + +[#reference_optional_operator_equal_optional] + +[: `optional& optional::operator= ( optional const& rhs ) ;`] + +* [*Effect:] Assigns another `optional` to an `optional`. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and +its value is a ['copy] of the value of `rhs`; else `*this` is uninitialized. +* [*Throws:] Whatever `T::operator( T const&)` or `T::T( T const& )` throws. +* [*Notes:] If both `*this` and `rhs` are initially initialized, `T`'s +['assignment operator] is used. If `*this` is initially initialized but `rhs` is +uninitialized, `T`'s [destructor] is called. If `*this` is initially uninitialized +but `rhs` is initialized, `T`'s ['copy constructor] is called. +* [*Exception Safety:] In the event of an exception, the initialization state of +`*this` is unchanged and its value unspecified as far as optional is concerned +(it is up to `T`'s `operator=()`). If `*this` is initially uninitialized and +`T`'s ['copy constructor] fails, `*this` is left properly uninitialized. +* [*Example:] +`` +T v; +optional opt(v); +optional def ; + +opt = def ; +assert ( !def ) ; +// previous value (copy of 'v') destroyed from within 'opt'. +`` + +__SPACE__ + +[: `optional & optional::operator= ( optional const& rhs ) ;`] + +* [*Effect:] (Re)binds thee wrapped reference. +* [*Postconditions:] If `*rhs` is initialized, `*this` is initialized and it +references the same object referenced by `*rhs`; otherwise, `*this` is +uninitialized (and references no object). +* [*Notes:] If `*this` was initialized and so is *rhs, this is is ['rebound] to +the new object. See [link optional_refassign here] for details on this behavior. +* [*Example:] +`` +int a = 1 ; +int b = 2 ; +T& ra = a ; +T& rb = b ; +optional def ; +optional ora(ra) ; +optional 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 orc(rc) ; +ora = orc ; // REBINDS ora to 'c' through 'rc' +c = 4 ; +assert ( *ora == 4 ) ; +`` + +__SPACE__ + +[#reference_optional_operator_equal_other_optional] + +[: `template optional& optional::operator= ( optional const& rhs ) ;`] + +* [*Effect:] Assigns another convertible optional to an optional. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and +its value is a ['copy] of the value of `rhs` ['converted] to type `T`; else +`*this` is uninitialized. +* [*Throws:] Whatever `T::operator=( U const& )` or `T::T( U const& )` throws. +* [*Notes:] If both `*this` and rhs are initially initialized, `T`'s +['assignment operator] (from `U`) is used. If `*this` is initially initialized +but `rhs` is uninitialized, `T`'s ['destructor] is called. If `*this` is +initially uninitialized but rhs is initialized, `T`'s ['converting constructor] +(from `U`) is called. +* [*Exception Safety:] In the event of an exception, the initialization state +of `*this` is unchanged and its value unspecified as far as optional is +concerned (it is up to `T`'s `operator=()`). If `*this` is initially +uninitialized and `T`'s converting constructor fails, `*this` is left properly +uninitialized. +* [*Example:] +`` +T v; +optional opt0(v); +optional opt1; + +opt1 = opt0 ; +assert ( *opt1 == static_cast(v) ) ; +`` + +__SPACE__ + +[#reference_optional_reset_value] + +[: `void optional::reset( T const& v ) ;`] +* [*Deprecated:] same as `operator= ( T const& v) ;` + +__SPACE__ + +[#reference_optional_reset] + +[: `void optional::reset() ;`] +* [*Deprecated:] Same as `operator=( detail::none_t );` + +__SPACE__ + +[#reference_optional_get] + +[: `T const& optional::operator*() const ;`] +[: `T& optional::operator*();`] +[: `T const& optional::get() const ;`] +[: `T& optional::get() ;`] + +[: `inline T const& get ( optional const& ) ;`] +[: `inline T& get ( optional &) ;`] + +* [*Requirements:] `*this` is initialized +* [*Returns:] A reference to the contained value +* [*Throws:] Nothing. +* [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. +* [*Example:] +`` +T v ; +optional opt ( v ); +T const& u = *opt; +assert ( u == v ) ; +T w ; +*opt = w ; +assert ( *opt == w ) ; +`` + +__SPACE__ + +[#reference_optional_get_value_or_value] + +[: `T const& optional::get_value_or( T const& default) const ;`] +[: `T& optional::get_value_or( T& default ) ;`] + +[: `inline T const& get_optional_value_or ( optional const& o, T const& default ) ;`] +[: `inline T& get_optional_value_or ( optional& o, T& default ) ;`] + +* [*Returns:] A reference to the contained value, if any, or `default`. +* [*Throws:] Nothing. +* [*Example:] +`` +T v, z ; +optional def; +T const& y = def.get_value_or(z); +assert ( y == z ) ; + +optional opt ( v ); +T const& u = get_optional_value_or(opt,z); +assert ( u == v ) ; +assert ( u != z ) ; +`` + +__SPACE__ + +[: `T const& optional::operator*() const ;`] +[: `T & optional::operator*();`] +[: `T const& optional::get() const ;`] +[: `T& optional::get() ;`] + +[: `inline T const& get ( optional const& ) ;`] +[: `inline T& get ( optional &) ;`] + +* [*Requirements: ] `*this` is initialized +* [*Returns:] [_The] reference contained. +* [*Throws:] Nothing. +* [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. +* [*Example:] +`` +T v ; +T& vref = v ; +optional opt ( vref ); +T const& vref2 = *opt; +assert ( vref2 == v ) ; +++ v ; +assert ( *opt == v ) ; +`` + +__SPACE__ + +[#reference_optional_get_ptr] + +[: `T const* optional::get_ptr() const ;`] +[: `T* optional::get_ptr() ;`] + +[: `inline T const* get_pointer ( optional const& ) ;`] +[: `inline T* get_pointer ( optional &) ;`] + +* [*Returns:] If `*this` is initialized, a pointer to the contained value; +else `0` (['null]). +* [*Throws:] Nothing. +* [*Notes:] The contained value is permanently stored within `*this`, so you +should not hold nor delete this pointer +* [*Example:] +`` +T v; +optional opt(v); +optional const copt(v); +T* p = opt.get_ptr() ; +T const* cp = copt.get_ptr(); +assert ( p == get_pointer(opt) ); +assert ( cp == get_pointer(copt) ) ; +`` + +__SPACE__ + +[#reference_optional_operator_arrow] + +[: `T const* optional::operator ->() const ;`] +[: `T* optional::operator ->() ;`] + +* [*Requirements: ] `*this` is initialized. +* [*Returns:] A pointer to the contained value. +* [*Throws:] Nothing. +* [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. +* [*Example:] +`` +struct X { int mdata ; } ; +X x ; +optional opt (x); +opt->mdata = 2 ; +`` + +__SPACE__ + +[#reference_optional_operator_bool] + +[: `optional::operator `['unspecified-bool-type]`() const ;`] + +* [*Returns:] An unspecified value which if used on a boolean context +is equivalent to (`get() != 0`) +* [*Throws:] Nothing. +* [*Example:] +`` +optional def ; +assert ( def == 0 ); +optional opt ( v ) ; +assert ( opt ); +assert ( opt != 0 ); +`` + +__SPACE__ + +[#reference_optional_operator_not] + +[: `bool optional::operator!() ;`] + +* [*Returns:] If `*this` is uninitialized, `true`; else `false`. +* [*Throws:] Nothing. +* [*Notes:] This operator is provided for those compilers which can't +use the ['unspecified-bool-type operator] in certain boolean contexts. +* [*Example:] +`` +optional opt ; +assert ( !opt ); +*opt = some_T ; + +// Notice the "double-bang" idiom here. +assert ( !!opt ) ; +`` + +__SPACE__ + +[#reference_optional_is_initialized] + +[: `bool optional::is_initialized() const ;`] + +* [*Returns: ] `true` if the `optional` is initialized, `false` otherwise. +* [*Throws:] Nothing. +* [*Example:] +`` +optional def ; +assert ( !def.is_initialized() ); +optional opt ( v ) ; +assert ( opt.is_initialized() ); +`` + +__SPACE__ + +[heading Free functions] + +__SPACE__ + +[#reference_make_optional_value] + +[: `optional make_optional( T const& v )`] + +* [*Returns: ] `optional(v)` for the ['deduced] type `T` of `v`. +* [*Example:] +`` +template void foo ( optional const& opt ) ; + +foo ( make_optional(1+1) ) ; // Creates an optional +`` + +__SPACE__ + +[#reference_make_optional_bool_value] + +[: `optional make_optional( bool condition, T const& v )`] + +* [*Returns: ] `optional(condition,v)` for the ['deduced] type `T` of `v`. +* [*Example:] +`` +optional calculate_foo() +{ + double val = compute_foo(); + return make_optional(is_not_nan_and_finite(val),val); +} + +optional v = calculate_foo(); +if ( !v ) + error("foo wasn't computed"); +`` + +__SPACE__ + +[#reference_operator_compare_equal_optional_optional] + +[: `bool operator == ( optional const& x, optional const& y );`] + +* [*Returns:] If both `x` and `y` are initialized, `(*x == *y)`. If only +`x` or `y` is initialized, `false`. If both are uninitialized, `true`. +* [*Throws:] Nothing. +* [*Notes:] Pointers have shallow relational operators while `optional` has +deep relational operators. Do not use `operator ==` directly in generic +code which expect to be given either an `optional` or a pointer; use +__FUNCTION_EQUAL_POINTEES__ instead +* [*Example:] +`` +T x(12); +T y(12); +T z(21); +optional def0 ; +optional def1 ; +optional optX(x); +optional optY(y); +optional 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 ) ; +`` + +__SPACE__ + +[#reference_operator_compare_less_optional_optional] + +[: `bool operator < ( optional const& x, optional const& y );`] + +* [*Returns:] If `y` is not initialized, `false`. If `y` is initialized +and `x` is not initialized, `true`. If both `x` and `y` are initialized, +`(*x < *y)`. +* [*Throws:] Nothing. +* [*Notes:] Pointers have shallow relational operators while `optional` has +deep relational operators. Do not use `operator <` directly in generic code +which expect to be given either an `optional` or a pointer; use __FUNCTION_LESS_POINTEES__ instead. +* [*Example:] +`` +T x(12); +T y(34); +optional def ; +optional optX(x); +optional 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 ) ; +`` + +__SPACE__ + +[#reference_operator_compare_not_equal_optional_optional] + +[: `bool operator != ( optional const& x, optional const& y );`] + +* [*Returns: ] `!( x == y );` +* [*Throws:] Nothing. + +__SPACE__ + +[#reference_operator_compare_greater_optional_optional] + +[: `bool operator > ( optional const& x, optional const& y );`] + +* [*Returns: ] `( y < x );` +* [*Throws:] Nothing. + +__SPACE__ + +[#reference_operator_compare_less_or_equal_optional_optional] + +[: `bool operator <= ( optional const& x, optional const& y );`] + +* [*Returns: ] `!( y= ( optional const& x, optional const& y );`] + +* [*Returns: ] `!( x& x, optional& y );`] + +* [*Effect:] If both `x` and `y` are initialized, calls `swap(*x,*y)` +using `std::swap`. If only one is initialized, say `x`, calls: +`y.reset(*x); x.reset();` If none is initialized, does nothing. +* [*Postconditions:] The states of `x` and `y` interchanged. +* [*Throws:] If both are initialized, whatever `swap(T&,T&)` throws. If only +one is initialized, whatever `T::T ( T const& )` throws. +* [*Notes:] If both are initialized, `swap(T&,T&)` is used unqualified but +with `std::swap` introduced in scope. +If only one is initialized, `T::~T()` and `T::T( T const& )` is called. +* [*Exception Safety:] If both are initialized, this operation has the +exception safety guarantees of `swap(T&,T&)`. +If only one is initialized, it has the same basic guarantee as +`optional::reset( T const& )`. +* [*Example:] +`` +T x(12); +T y(21); +optional def0 ; +optional def1 ; +optional optX(x); +optional 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 ); +`` + +[endsect] diff --git a/doc/special_cases.qbk b/doc/special_cases.qbk new file mode 100644 index 0000000..be65f6b --- /dev/null +++ b/doc/special_cases.qbk @@ -0,0 +1,376 @@ + +[section Optional references] + +This library allows the template parameter `T` to be of reference type: +`T&`, and to some extent, `T const&`. + +However, since references are not real objects some restrictions apply and +some operations are not available in this case: + +* Converting constructors +* Converting assignment +* InPlace construction +* InPlace assignment +* Value-access via pointer + +Also, even though `optional` treats it wrapped pseudo-object much as +a real value, a true real reference is stored so aliasing will ocurr: + +* Copies of `optional` will copy the references but all these references +will nonetheless reefer to the same object. +* Value-access will actually provide access to the referenced object +rather than the reference itself. + +[endsect] + +[#optional_refassign] + +[section Rebinding semantics for assignment of optional references] + +If you assign to an ['uninitialized ] `optional` the effect is to bind (for +the first time) to the object. Clearly, there is no other choice. + + int x = 1 ; + int& rx = x ; + optional ora ; + optional orb(x) ; + ora = orb ; // now 'ora' is bound to 'x' through 'rx' + *ora = 2 ; // Changes value of 'x' through 'ora' + assert(x==2); + +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. + + 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' + +Now, if you assign to an ['initialized ] `optional`, the effect is to +[*rebind] to the new object instead of assigning the referee. This is unlike +bare C++ references. + + int a = 1 ; + int b = 2 ; + int& ra = a ; + int& rb = b ; + optional ora(ra) ; + optional orb(rb) ; + ora = orb ; // 'ora' is rebound to 'b' + *ora = 3 ; // Changes value of 'b' (not 'a') + assert(a==1); + assert(b==3); + +[heading Rationale] + +Rebinding semantics for the assignment of ['initialized ] `optional` references has +been chosen to provide [*consistency among initialization states] even at the +expense of lack of consistency with the semantics of bare C++ references. +It is true that `optional` 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. + +Imagine `optional` forwarding assignment to the referenced object (thus +changing the referenced object value but not rebinding), and consider the +following code: + + optional a = get(); + int x = 1 ; + int& rx = x ; + optional b(rx); + a = b ; + +What does the assignment do? + +If `a` is ['uninitialized], the answer is clear: it binds to `x` (we now have +another reference to `x`). +But what if `a` is already ['initialized]? it would change the value of the +referenced object (whatever that is); which is inconsistent with the other +possible case. + +If `optional` 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. + +That is, you would have to discriminate in order to be consistency. + +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 ['uninitialized ] `optional` 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. +In such scenario, you can assign the value itself directly, as in: + + assert(!!opt); + *opt=value; + +[endsect] + +[#optional_in_place_factories] + +[section In-Place Factories] + +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 __COPY_CONSTRUCTIBLE__, but also requires the existence of +a fully constructed object, often temporary, just to follow the copy from: + + struct X + { + X ( int, std:::string ) ; + } ; + + class W + { + X wrapped_ ; + + public: + + W ( X const& x ) : wrapped_(x) {} + } ; + + void foo() + { + // Temporary object created. + W ( X(123,"hello") ) ; + } + +A solution to this problem is to support direct construction of the +contained object right in the container's storage. +In this scheme, the user only needs to supply the arguments to the +constructor to use in the wrapped object construction. + + class W + { + X wrapped_ ; + + public: + + W ( X const& x ) : wrapped_(x) {} + W ( int a0, std::string a1) : wrapped_(a0,a1) {} + } ; + + void foo() + { + // Wrapped object constructed in-place + // No temporary created. + W (123,"hello") ; + } + +A limitation of this method is that it doesn't scale well to wrapped +objects with multiple constructors nor to generic code were the constructor +overloads are unknown. + +The solution presented in this library is the family of [*InPlaceFactories] +and [*TypedInPlaceFactories]. +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. + +For example, one member of this family looks like: + + template + 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) ; } + } ; + +A wrapper class aware of this can use it as: + + class W + { + X wrapped_ ; + + public: + + W ( X const& x ) : wrapped_(x) {} + W ( TypedInPlaceFactory2 const& fac ) { fac.construct(&wrapped_) ; } + } ; + + void foo() + { + // Wrapped object constructed in-place via a TypedInPlaceFactory. + // No temporary created. + W ( TypedInPlaceFactory2 + InPlaceFactoryN in_place ( A0 const& a0, ..., AN const& aN) ; + + template + TypedInPlaceFactoryN in_place ( T const& a0, A0 const& a0, ..., AN const& aN) ; + +In-place factories can be used generically by the wrapper and user as follows: + + class W + { + X wrapped_ ; + + public: + + W ( X const& x ) : wrapped_(x) {} + + template< class InPlaceFactory > + W ( InPlaceFactory const& fac ) { fac.template construct(&wrapped_) ; } + + } ; + + void foo() + { + // Wrapped object constructed in-place via a InPlaceFactory. + // No temporary created. + W ( in_place(123,"hello") ) ; + } + +The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYPED_IN_PLACE_FACTORY_HPP__ + +[endsect] + +[section A note about optional] + +`optional` should be used with special caution and consideration. + +First, it is functionally similar to a tristate boolean (false,maybe,true) +—such as __BOOST_TRIBOOL__— except that in a tristate boolean, the maybe state +[_represents a valid value], unlike the corresponding state of an uninitialized +`optional`. +It should be carefully considered if an `optional` instead of a `tribool` +is really needed. + +Second, `optional<>` provides an implicit conversion to `bool`. This +conversion refers to the initialization state and not to the contained value. +Using `optional` can lead to subtle errors due to the implicit `bool` +conversion: + + void foo ( bool v ) ; + void bar() + { + optional v = try(); + + // The following intended to pass the value of 'v' to foo(): + foo(v); + // But instead, the initialization state is passed + // due to a typo: it should have been foo(*v). + } + +The only implicit conversion is to `bool`, and it is safe in the sense that +typical integral promotions don't apply (i.e. if `foo()` takes an `int` +instead, it won't compile). + +[endsect] + +[section Exception Safety Guarantees] + +Because of the current implementation (see [link optional_implementation_notes Implementation Notes]), all of the assignment methods: + +* `optional::operator= ( optional const& )` +* `optional::operator= ( T const& )` +* `template optional::operator= ( optional const& )` +* `template optional::operator= ( InPlaceFactory const& )` +* `template optional::operator= ( TypedInPlaceFactory const& ) ` +* `optional:::reset ( T const&)` + +Can only ['guarantee] the [_basic exception safety]: The lvalue optional is +left [_uninitialized] if an exception is thrown (any previous value is ['first] +destroyed using `T::~T()`) + +On the other hand, the ['uninitializing] methods: + +* `optional::operator= ( detail::none_t )` +* `optional::reset()` + +Provide the no-throw guarantee (assuming a no-throw `T::~T()`) + +However, since `optional<>` 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. + + // + // Case 1: Exception thrown during assignment. + // + T v0(123); + optional opt0(v0); + try + { + T v1(456); + optional 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 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 ) ; + } + +[heading Swap] + +`void swap( optional&, optional& )` has the same exception guarantee +as `swap(T&,T&)` when both optionals are initialized. +If only one of the optionals is initialized, it gives the same ['basic] +exception guarantee as `optional::reset( T const& )` (since +`optional::reset()` doesn't throw). +If none of the optionals is initialized, it has no-throw guarantee +since it is a no-op. + +[endsect] + +[section Type requirements] + +In general, `T` must be __COPY_CONSTRUCTIBLE__ and have a no-throw destructor. +The copy-constructible requirement is not needed if [*InPlaceFactories] are used. + +`T` [_is not] required to be __SGI_DEFAULT_CONSTRUCTIBLE__. + +[endsect] + +