...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
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:
optional<T
(not
a ref)>
, the description
corresponds only to the case where T
is not of reference type.
optional<T&>
,
the description corresponds only to the case where T
is of reference type.
optional<T>
,
the description is the same for both cases.
Note | |
---|---|
The following section contains various |
optional<T>::optional();
optional
.
*this
is uninitialized.
optional<T> def ; assert ( !def ) ;
optional<T>::optional( none_t );
optional
uninitialized.
*this
is uninitialized.
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.
#include <boost/none.hpp> optional<T> n(none) ; assert ( !n ) ;
optional<T
(not a ref)>::optional( T const& v )
optional
.
*this
is initialized
and its value is acopy of v
.
T::T(
T const& )
throws.
T::T(
T const& )
is
called.
T::T( T
const&
);
in that case, this constructor
has no effect.
T v; optional<T> opt(v); assert ( *opt == v ) ;
optional<T&>::optional( T& ref )
optional
.
*this
is initialized
and its value is an instance of an internal type wrapping the reference
ref
.
T v; T& vref = v ; optional<T&> opt(vref); assert ( *opt == v ) ; ++ v ; // mutate referee assert (*opt == v);
optional<T
(not a ref)>::optional( bool condition, T const& v ) ;
optional<T&> ::optional( bool condition, T& v ) ;
optional<T
(not a ref)>::optional( T const& v )
optional<T&> ::optional( T& v )
optional<T ['(not a ref)]>::optional()
optional<T&> ::optional()
optional<T
(not a ref)>::optional( optional const& rhs );
optional
.
*this
is initialized and its value is a copy of the value
of rhs
; else *this
is uninitialized.
T::T(
T const& )
throws.
T::T(T const& )
is
called.
T::T( T
const&
);
in that case, this constructor
has no effect.
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 ) ;
optional<T&>::optional( optional const& rhs );
optional
.
rhs
is initialized, *this
is initialized and its value is another reference to the same object referenced
by *rhs
;
else *this
is uninitialized.
rhs
is initialized, both *this
and *rhs
will reefer to the same object (they alias).
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 ) ;
template<U> explicit optional<T
(not a ref)>::optional( optional<U> const& rhs );
optional
.
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.
T::T(
U const& )
throws.
T::T(
U const& )
is
called if rhs
is initialized,
which requires a valid conversion from U
to T
.
T::T( U
const&
);
in that case, this constructor
has no effect.
optional<double> x(123.4); assert ( *x == 123.4 ) ; optional<int> y(x) ; assert( *y == 123 ) ;
template<InPlaceFactory> explicit optional<T
(not a ref)>::optional( InPlaceFactory const& f );
template<TypedInPlaceFactory> explicit optional<T
(not a ref)>::optional( TypedInPlaceFactory const& f );
optional
with a value of T
obtained
from the factory.
*this
is initialized
and its value is directly given from the factory f
(i.e., the value is
not copied).
T
constructor called by the factory throws.
T
constructor used by the factory; in that case, this constructor has no effect.
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 ) ;
optional& optional<T
(not a ref)>::operator= ( T const& rhs ) ;
rhs
to an optional
.
*this
is initialized and its value is a copy
of rhs
.
T::operator=( T const& )
or
T::T(T
const&)
throws.
*this
was initialized, T
's
assignment operator is used, otherwise, its copy-constructor is used.
*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.
T x; optional<T> def ; optional<T> opt(x) ; T y; def = y ; assert ( *def == y ) ; opt = y ; assert ( *opt == y ) ;
optional<T&>& optional<T&>::operator= ( T& const& rhs ) ;
*this
is initialized and it references the
same object referenced by rhs
.
*this
was initialized, is is rebound
to the new object. See here
for details on this behavior.
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 ) ;
optional& optional<T
(not a ref)>::operator= ( optional const& rhs ) ;
optional
to an optional
.
rhs
is initialized, *this
is initialized and its value is a copy of the value
of rhs
; else *this
is uninitialized.
T::operator( T const&)
or T::T(
T const& )
throws.
*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.
*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.
T v; optional<T> opt(v); optional<T> def ; opt = def ; assert ( !def ) ; // previous value (copy of 'v') destroyed from within 'opt'.
optional<T&> & optional<T&>::operator= ( optional<T&> const& rhs ) ;
*rhs
is initialized, *this
is initialized and it references the
same object referenced by *rhs
; otherwise, *this
is uninitialized (and references no object).
*this
was initialized and so is *rhs, this
is is rebound to the new object. See here
for details on this behavior.
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 ) ;
template<U> optional& optional<T
(not a ref)>::operator= ( optional<U> const& rhs ) ;
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.
T::operator=( U const& )
or
T::T( U
const&
)
throws.
*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.
*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.
T v; optional<T> opt0(v); optional<U> opt1; opt1 = opt0 ; assert ( *opt1 == static_cast<U>(v) ) ;
void optional<T
(not a ref)>::reset( T const& v ) ;
operator= ( T
const&
v) ;
void optional<T>::reset() ;
operator=( detail::none_t );
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)> &) ;
*this
is initialized
BOOST_ASSERT()
.
T v ; optional<T> opt ( v ); T const& u = *opt; assert ( u == v ) ; T w ; *opt = w ; assert ( *opt == w ) ;
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 ) ;
default
.
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 ) ;
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&> &) ;
*this
is initialized
BOOST_ASSERT()
.
T v ; T& vref = v ; optional<T&> opt ( vref ); T const& vref2 = *opt; assert ( vref2 == v ) ; ++ v ; assert ( *opt == v ) ;
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)> &) ;
*this
is initialized, a pointer to the contained
value; else 0
(null).
*this
,
so you should not hold nor delete this pointer
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) ) ;
T const* optional<T
(not a ref)>::operator ->() const ;
T* optional<T
(not a ref)>::operator ->() ;
*this
is initialized.
BOOST_ASSERT()
.
struct X { int mdata ; } ; X x ; optional<X> opt (x); opt->mdata = 2 ;
optional<T>::operator
unspecified-bool-type() const ;
get() != 0
)
optional<T> def ; assert ( def == 0 ); optional<T> opt ( v ) ; assert ( opt ); assert ( opt != 0 );
bool optional<T>::operator!() ;
*this
is uninitialized, true
;
else false
.
optional<T> opt ; assert ( !opt ); *opt = some_T ; // Notice the "double-bang" idiom here. assert ( !!opt ) ;
bool optional<T>::is_initialized() const ;
true
if the optional
is initialized,
false
otherwise.
optional<T> def ; assert ( !def.is_initialized() ); optional<T> opt ( v ) ; assert ( opt.is_initialized() );
optional<T
(not a ref)> make_optional( T const& v )
optional<T>(v)
for
the deduced type T
of v
.
template<class T> void foo ( optional<T> const& opt ) ; foo ( make_optional(1+1) ) ; // Creates an optional<int>
optional<T
(not a ref)> make_optional( bool condition, T const& v )
optional<T>(condition,v)
for
the deduced type T
of v
.
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");
bool operator == ( optional<T> const& x, optional<T> const& y );
x
and y
are initialized, (*x ==
*y)
. If only x
or y
is initialized, false
. If both are uninitialized, true
.
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
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 ) ;
bool operator < ( optional<T> const& x, optional<T> const& y );
y
is not initialized, false
. If
y
is initialized and x
is not initialized, true
.
If both x
and y
are initialized, (*x < *y)
.
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.
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 ) ;
bool operator != ( optional<T> const& x, optional<T> const& y );
!(
x ==
y );
bool operator > ( optional<T> const& x, optional<T> const& y );
(
y <
x );
bool operator <= ( optional<T> const& x, optional<T> const& y );
!(
y<x );
bool operator >= ( optional<T> const& x, optional<T> const& y );
!(
x<y );
void swap ( optional<T>& x, optional<T>& y );
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.
x
and y
interchanged.
swap(T&,T&)
throws. If only one is initialized, whatever T::T (
T const& )
throws.
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.
swap(T&,T&)
.
If only one is initialized, it has the same basic guarantee as optional<T>::reset( T const& )
.
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 );