Header <boost/optional.hpp>

Contents

Motivation
Developing a wrapper for optional values.
Synopsis
Semantics
Usage
Comparison of Value Access operations
Exception Safety Guarantees
Type requirements
Implementation Notes
Dependencies and Portability
Acknowledgment

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 asssert in a debug build) or uses a runtime check and throws an exception if the postcondition is violated. This is a reasonable design 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 'char' value to return; so it is not correct 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 inexisting 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, but 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.

Developing a wrapper for optional values.

The model

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 inilializer (an initial value is given), it is said that the object has been initialized.
If the declaration does not include a non-empty initializer (no initial value is given), it is said that the object is uninitialized. Its actual value exist but has an indeterminate inital value (c.f. 8.5.9).
optional<T> intends to formalize the notions of initialization/uninitialization allowing a program to test whether an object has been initialized and defining that access to the value of an uninitialized object is undefined behaviour.
That is, when a variable is declared of optional type T, and a value for it is not given, the variable is formally uninitialized. A formally uninitialized optional object has conceptually no value at all and this situation can be tested. It is formally undefined behvaiour 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. And given the formal treatment of initialization states in optional objects, it is even possible to reset an optional to uninitialized.

However, 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 whether you have effectively initialized the object.
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 possibles values of a given type. On modern languages, this can be modeled with a discriminated union of T and something else such as a trivial POD type or enum. Discriminated unions are often called variants. A variant has a current type, which in our case is either T or nil_t, and in C++, our specific variant would be typically implemented as a template class of the form: variant<T,nil_t>

There is precedence for the discriminated union as a model for an optional value: the Haskell maybe builtin type constructor.
A discriminated union, which can be seen as a container which has an object of either type T or nil_t, has exactly the semantics required for a wrapper of optional values:

  • deep-copy semantics: copies of the variant implies copies of the contained value.
  • deep-relational semantics: comparions 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 behaviour of trying to access the value of an uninitialized optional
  • However, because the discriminated union is used for this purpose in such a way that it only matters whether it's current type is T or not, we can put a layer on top of the variant model hidding the other type (nil_t), transforming the container of fixed size 1 into a variable size container which either has a T or has nothing.

    A variable-size fixed capacity (of 1) stack based container to serve the purposes of an optional wrapper could have the following interface:

    optional<T>::optional(); // Uninitialized.
    
    optional<T>::optional( T const& v ) ; // Initialized with v
    
    void optional<T>::reset(); // Back to uninitialized
    
    void optional<T>::reset( T const& v ) ; // Assigns 'v' whether previously initialized or not.
    
    bool optional<T>::initialized() ; 
    
    // Returns a reference to the value if initialized; otherwise, the result is undefined.
    T const& optional<T>::ref() const ; 
    T&       optional<T>::ref() ;
    
    // If both are initialized, calls swap(T&,T&);
    // If only one is initialized, uses reset(T const&) and reset().
    // If both are uninitalized, do nothing.
    void swap ( optional<T>& lhs, optional<T>& rhs ) ;
    
    // If both are initialized, compare values.
    // If only one is initialized, they are not equal.
    // If both are uninitalized,they are equal.
    bool operator == ( optional<T> const& lhs, optional<T> const& rhs ) ;
    bool operator != ( optional<T> const& lhs, optional<T> const& rhs ) ;
    

    Pointers and optional objects

    In C++, unlike many other languages, objects can be referenced indirectly by means of a pointer (or a reference). Pointers have several nice features, two of which are relevant to this development.

    One of them is that pointers have their own values, and these pointer values are what references the object being pointed to (the pointee). Consequently, copies of pointers do not imply copies of pointees. This effect is called aliasing, and the important fact about aliasing is that different pointers can refer to the same object. The particular semantic that a copy of a pointer does not involve a copy of the pointee is called shallow-copy, as opossed to deep-copy were a copy if a wrapper involves a copy of the wrapped object, as with optional<>
    Since this is the semantic followed by pointers (and references), shallow-copy (and therefore aliasing) is implied in pointer semantics.

    The other relevant feature of a pointer is that a pointer 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 a non-existing object.

    The special meaning of the null pointer value allowed pointers to became a defacto standard for handling optional objects because all you have to do to hand out a value which you don't really have is to give 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 non existing) 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()), implicitely convey the notion of optionality, and this information is tied to the syntax of those 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.
    Furthermore, the existence of the pointee can be test by a comparison against the null pointer value, via a conversion to bool, which allows expressions of the from: if ( p ), or if ( p != 0 ) to be used to test the existence of the pointee.

    Such a defacto idiom for refering to optional objects can be formalized in the form of a concept: the OptionalPointee concept.
    This concept captures the syntatic usage of operatos *, -> 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 the function context into the caller 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 builtin or small POD, this technique is very poor in terms of required resources. Otional 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 unapprorpiate 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.
    Therefore, the final solution which is presented in this library is to shape the previously discussed optional as a container as a model of the OptionalPointee concept.

    The container-like optional wrapper as a model of OptionalPointee

    The container-like optional model presented before has value-semantics. It features deep-copy and deep relational operators, consequently, it does not model a pointer. However, this library provides an optional wrapper which also models the OptionalPointee concept, which means that instead of the member function 'initialized()' as shown before it has a safe conversion to bool, and instead of the 'ref()' member function, it has operators*() and ->().
    However, it is particularly important that optional<> objects are not mistaken by pointers, they are not. Optionals do not show shallow-copy thus do not alias: two different optionals never point to the same value (but my have equivalent values).
    The difference between an optional and a pointer must be kept in mind particularly as the semantics of relational operators are different: since optional is a value-wrapper, relational operators are deep: i.e., they compare optional values; but relational operators for pointers are shallow: i.e., 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, you cannot use relational operators directly, and must use the template function equal_pointee() instead.

    This helper function is already provided in the optional header and is used in the implementation of optional<>'s operators == and != since these operators have deep semantics (i.e, unlike pointers, compare pointee values and not pointer values)


    Synopsis

    namespace boost {
    
    template<class T>
    class optional
    {
      public :
    
        optional () ;
    
        explicit optional ( T const& v ) ;
    
        optional ( optional const∓ rhs ) ;
    
        template<class U>
        explicit optional ( optional<U> const& rhs ) ;
    
        optional& operator = ( optional const& rhs ) ;
    
        template<class U>
        optional& operator = ( optional<U> const& rhs ) ;
    
        T const* get() const ;
        T*       get() ;
    
        T const* operator ->() const ;
        T*       operator ->() ;
    
        T const& operator *() const ;
        T&       operator *() ;
    
        void reset();
    
        void reset ( T const& ) ;
    
        operator unspecified-bool-type() const ;
    
        bool operator!() const ;
    
    } ;
    
    template<class T> inline bool operator == ( optional<T> const& x, optional<T> const& y ) ;
    
    template<class T> inline bool operator != ( optional<T> const& x, optional<T> const& y ) ;
    
    template<class T> inline T* get_pointer ( optional<T> const& opt ) ;
    
    template<class T> inline void swap( optional<T>& x, optional<T>& y ) ;
    
    } // namespace boost
    

    Semantics

    Note: the following section contains asserts() with several expressions. This is used only to show the invariants that hold after the each preceding operation. It is not implied that the type T must support each particular expression (such as comparisons)


    optional<T>::optional();

    Default-Constructs an uninitialized optional.
    T's default constructor is not called
    Does NOT throw.

    optional<T> def ;
    assert ( !def ) ;

    explicit optional<T>::optional( T const& v )

    Directly-Constructs an initialized optional holding a copy of the value 'v'.
    Calls T's copy-constructor.
    It can throw whatever T::T ( T const&) can throw, but no internal resources are leaked.

    T v;
    optional<T> opt(v);
    assert ( *opt == v ) ;
    

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

    Copy-Constructs a copy of another optional 'rhs'.
    If 'rhs' is initialized, it also copies the value rhs holds.
    In that case, it uses T's copy-constructor and it can throw whatever T::T ( T const&) can throw, but no internal resources are leaked.

    optional<T> uninit ;
    assert (!uninit);
    
    optional<T> uinit2 ( uninit ) ;
    assert (!uninit2);
    
    optional<T> init( T(2) );
    assert ( *init == T(2) ) ;
    
    optional<T> init2 = init ;
    assert( *init2 == T(2) ) ;
    

    explicit template<U>optional<T>::optional(optional≷U> const& rhs);

    Copy-Constructs a copy of another convertible optional 'rhs' of a different wrapped type.
    If 'rhs' is initialized, it also copies the value rhs holds converted to T.
    In that case, it uses T's converting-copy-constructor and it can throw whatever T::T ( U const&) can throw, but no internal resources are leaked
    U must be convertible to T for this to compile.

    optional<int> x(1234);
    assert ( *x == 1234 ) ;
    
    optional<double> y(x) ;
    assert( *y == 1234.0 ) ;
    

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

    Assigns a copy of another optional 'rhs'.
    If 'rhs' is initialized, it also copies the value rhs holds. In that case, it uses T's copy-constructor, and the resulting state is initialized.
    If 'rhs' is uninitialized, the resulting state is uninitialized.

    If 'this' is initialized, its previous value is destroyed, using T::~T(), before the copy begins.

    See also Exception Safety Guarantees

    T v;
    optional<T> opt(v);
    optional<T> uninit ;
    
    opt = uninit ;
    assert ( !opt ) ;
    // previous value (copy of 'v') destroyed from within 'opt'.
    
    

    template<U>optional& optional<T>::operator= ( optional≷U> const& rhs ) ;

    Assigns a copy of another convertible optional 'rhs'.
    If 'rhs' is initialized, it also copies the value rhs holds converted to T. In that case, it uses T's converting-copy-constructor, and the resulting state is initialized.
    If 'rhs' is uninitialized, the resulting state is uninitialized.

    If 'this' is initialized, its previous value is destroyed, using T::~T(), before the copy begins.

    U must be convertible to T for this to compile.
    See also Exception Safety Guarantees

    T v;
    optional<T> opt0(v);
    optional<U> opt1;
    
    opt1 = opt0 ;
    assert ( *opt1 == static_cast(v) ) ;
    

    void optional<T>::reset( T const& v ) ;

    If the optional is uninitialized, initializes it copying the initializer value 'v' using T::T ( T const&).

    If the optional is initialized, replaces its value with 'v', destroying the previous value using T::~T() and copying the initializer 'v'.
    If T::~T() throws during the uninitialization, the resulting state is undefined.

    See also Exception Safety Guarantees

    optional<T> opt ( some_T ) ;
    assert( *opt == some_T );
    opt.reset ( some_other_T ) ;
    assert( *opt == some_other_T );
    

    void optional<T>::reset() ;

    Uninitializes the optional.
    If it is initialized, it destroys its value, using T::~T().
    If T::~T() throws during the uninitialization, the resulting state is undefined.

    optional<T> opt ( some_T ) ;
    assert( *opt == some_T );
    opt.reset();
    assert( !opt );
    

    T const* optional<T>::get() const ;
    T*       optional<T>::get() ;
    
    inline T const* get_pointer ( optional<T> const& ) ;
    inline T*       get_pointer ( optional<T>&) ;
    

    Returns a pointer to the optional value (of type T).
    If the optional object is uninititialized returns NULL.
    Note: it doesn't return a managed pointer, so ownership is not transferred (a call to delete on the result is undefined behavior)
    See also Comparison of Value Access operations.

    T v;
    optional<T> opt(v);
    optional<T> const copt(v);
    T* p = opt.get() ;
    T const* cp = copt.get();
    assert ( p == get_pointer(opt) );
    assert ( cp == get_pointer(copt) ) ;
    

    T const* optional<T>::operator ->() const ;
    T*       optional<T>::operator ->()       ;
    

    If the optional object is initialized, returns a pointer to its value (of type T), otherwise, the result is undefined (but BOOST_ASSERT is used so the user can define this behavior in a debug build).

    struct X { int mdata ; } ;
    X x ;
    optional<X> opt (x);
    opt->mdata = 2 ;
    

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

    If the optional object is initialized, returns a reference to its value (of type T).
    If it is uninitialized, the result is undefined (but BOOST_ASSERT is used so the user can define this behavior in a debug build).

    T v ;
    optional<T> opt ( v );
    T const& u = *opt;
    assert ( u == v ) ;
    T w ;
    *opt = w ;
    assert ( *opt == w ) ;
    

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

    Returns an unspecified value which if used on a boolean context is equivalent to (get() != 0)

    optional<T> def ;
    assert ( def == 0 );
    optional<T> opt ( v ) ;
    assert ( opt );
    assert ( opt != 0 );
    

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

    Returns true if the optional is uninitialized, false otherwise.


    optional<T> opt ; assert ( !opt ); *opt = some_T ; // Notice the "double-bang" idiom here. assert ( !!opt ) ;

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

    operator == compares both initialization states and values. It is directly implemented as a call to equal_pointees()

    Note: Always remember that pointers have shallow relational operators while optional has deep relational operators. Do not use this operators directly in generic code which expect to recieve either an optional or a pointer. Use equal_pointees() instead in that case.

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

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

    If both x and y are initialized, calls swap(*x,*y) (introducing std::swap first).
    If only one is initialized, say, 'i' is initialized and 'u' isn't, calls u.reset(*i) and i.reset().
    If both are uninitialized, does nothing.
    See also Exception Safety Guarantees

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

    Usage

    An object of type optional<T> can be used to hold a value of type T which might be uninitialized.
    As any value wrapper, it has value semantics (in spite of its partly pointer-like interface)

    The following cases present the overall usage:

    //
    // Usage Case A: Functions which may not have a value to return but cannot treat
    // this situation as an error.
    //
    optional<char> get_async_input()
    {
      if ( !queue.empty() )
           return optional<char>(queue.top());
      else return optional<char>(); // uninitialized
    }
    
    void recieve_async_message()
    {
      optional<char> rcv ;
      while ( (rcv = get_async_input()) && !timeout() )
        output(*rcv);
    }
    
    //
    // Usage Case B: Local variable which is never assigned a value.
    //
    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!");
    
    
    //
    // Usage Case C: Data member which can remain uninitialized.
    //
    class figure
    {
      public:
    
        figure()
        {
          // data member clipping rect is uninitialized at this point.
        }
    
        void clip_in_rect ( rect const& rect )
          {
             ....
             m_clipping_rect.reset ( rect ) ; // initialized here.
          }
    
        rect const* get_clipping_rect() // this can return NULL.
          { return get(m_clipping_rect); }
    
      private :
    
        optional<rect> m_clipping_rect ;
    
    };
    

    Special usage: A default constructed optional<T> does not call T's default constructor. This makes optional suitable as a mechanism to bypass the default constructor when it is particularly expensive and when default construction is unnecesary.


    Comparison of Value-Access operations

    optional<> has functions/operators to access its value by pointer or reference:

    by-pointer:
    inline T const* get_pointer ( optional<> const& ); inline T* get_pointer ( optional<>& );
    T const* optional<>::get() const; T* optional<>::get(); by-reference: T const& optional<>::operator* () const; T& optional<>::operator* ();

    The first group, since they return a pointer, have defined behavior even with uninitialized optionals (NULL is returned in such a case).
    The second group, on the other hand, since they return references, have undefined behavior with uninitialized optionals (though this behavior can be defined by the user via control of BOOST_ASSERT since they all test the precondition 'is initialized' in debug builds).

    get() (and get_pointer()) can be used in those cases were the uninitialized state is expected, and it is convenient to handle it directly through a built-in pointer. This is typically expressed with the following idiom (due to Peter Dimov):

    optional<T> r = Try();
    if ( T* result = get_pointer(r) )
    {
      // use *result here.
    }
    else
    {
      // don't use *result here, 'r' is uninitialized.
    }
    
    Conversely, operator*() can be used in those cases were the uninitialized state is unexpected.
    Trying to access the value of an uninitialized optional is undefined behaviour. In debug build, it will raise a precondition violation, the exact effect of which depends on the user settings for Boost Assertions.

    struct X
    {
      void DoSome();
      optional<data_type> mData ;
    } ;
    void X::DoSome()
    {
      // it is unexpected that 'mData' be uninitialized here.
      if ( *mData == Value )
      {
        // mData is initialized and its value is 'Value'
      }
      else
      {
        // mData is initialized, but its value is not 'Value'
      }
    }
    

    There is another access method which returns a pointer but has undefined behaviour in the case of uninitialized state, just as the methods which return a reference:

    T const* optional<T>::operator ->() const ;
    T*       optional<T>::operator ->();

    Exception Safety Guarantees

    Since optional<T> is a wrapper for arbitrary types T, it can only guarantee the basic exception safety.

    The only source for exceptions is T's copy constructor. That is, optional<> itself doesn't throw any exceptions since it doesn't allocate any resources (see Implementation Notes). If you know the exception guarantees for T, you know that optional<T> has the same guarantees.

    Assignment: optional's assignment offers the basic guarantee for the general case (assuming T's copy constructor can throw): the lvalue optional is reset to uninitialized (its previous value is destroyed using T::~T())

    //
    // Case 1: Exception thrown during assignment.
    //
    T v0(0);
    optional<T> opt0(v0);
    try
    {
      T v1(1);
      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 Value-assignment (through reset)
    //
    T v0(0);
    optional<T> opt0(v0);
    try
    {
      T v2(2);
      opt0.reset ( v2 ) ;
    
      // If no exception was thrown, assignment succeeded.
      assert( *opt0 == v2 ) ;
    }
    catch(...)
    {
      // If any exception was thrown, 'opt0' is reset to uninitialized.
      assert( !opt0 ) ;
    }
    

    Swap: optional's swap 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 exception guarantee as optional<T>::reset( T const& ) (since reset() does not throw).
    If none of the optionals is initialized, since it is a no-op, it has no-throw guarantee.


    Type requirements

    The only requirements for the wrapped type T is that it has an accessible copy constructor and no-throw destructor.
    Default constructor is not required.


    Implementation Notes

    optional<T> is currently implemented using make_aligned_storage<T>::type (from utility/aligned_storage.hpp), and uses a separate boolean flag to indicate the initialization state.
    As a result of this choice of implementation, T's default constructor is effectively by-passed. Placement new with T's copy constructor and T's destructor are explicitely used to initialize,copy and destroy optional values.
    However, the implementation could have used a discriminated union as discussed in the introduction, and it probably will when boost::variant arrives.


    Dependencies and Portability

    This class uses utility/aligned_storage.hpp

    It has been tested on bcc5.5.1


    Acknowledgments

    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:


    Revised 21 November 2002

    © Copyright boost.org 2002. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.

    Developed by Fernando Cacciola, the latest version of this file can be found at www.boost.org, and the boost discussion list at www.yahoogroups.com/list/boost.