/* * * Copyright (C) 2014, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: ofstd * * Author: Jan Schlamelcher * * Purpose: Implementing optional types similar to boost::optional * or the std::optional proposal N3690. */ #ifndef OFOPTION_H #define OFOPTION_H #include "dcmtk/config/osconfig.h" // make sure OS specific configuration is included first #include "dcmtk/ofstd/oftypes.h" #include "dcmtk/ofstd/ofutil.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/ofstd/ofdefine.h" #include "dcmtk/ofstd/oftraits.h" #include "dcmtk/ofstd/ofalign.h" // include for "std::is_default_constructible" // to recover from compiler insanity (Visual Studio 12+). #if defined(_MSC_VER) && _MSC_VER >= 1700 #include #endif #ifndef DOXYGEN struct OFnullopt_t {}; #ifdef DCMTK_USE_CXX11_STL // declare constexpr nullopt if supported. constexpr OFnullopt_t OFnullopt{}; #else // C++11 // declare extern nullopt if constexpr is not supported. extern DCMTK_OFSTD_EXPORT OFnullopt_t OFnullopt; #endif // NOT C++11 #else // NOT DOXYGEN /** OFnullopt_t is the type of the global constant @ref OFnullopt "@c OFnullopt" * referring to a disengaged OFoptional object independent of the content type. * @typedef OFnullopt_t * OFnullopt_t may be used to improve the performance of overloaded methods, see example: * @code{.cpp} * int add2( const OFoptional& o ) * { * return o ? *o + 2 : 2; * } * * int add2( OFnullopt_t ) * { * // Note: it's not required to check the state when OFnullopt is passed. * return 2; * } * @endcode * @relates OFoptional */ unspecified OFnullopt_t; /** A wildcard global constant to initialize an OFoptional object with disengaged state. * @details * @b Example: * @code{.cpp} * OFoptional div( int lhs, int rhs ) * { * return rhs ? OFmake_optional( lhs / rhs ) : OFnullopt; * } * @endcode * @relates OFoptional * @see OFoptional */ OFnullpt_t OFnullopt; #endif // DOXYGEN /** Default storage traits of OFoptional. * OFdefault_optional_traits manages the state and storage of the contained * object in a portable manner. You may use this class as base when defining * custom traits for a specific type T, so you won't have to re-implement * this functionality entirely. * @relates OFoptional * @tparam T the content type of the respective OFoptional instance. * @sa OFoptional * @sa OFoptional_traits * @details *

@anchor ofoptional_trait_override Example

* This example shows how to override the is_default_constructible * attribute of OFoptional_traits for the custom class Test. * @code * // Note: Test's default constructor is private * // which leads to errors when being used within * // OFoptional, since a default constructor exists * // but can't be accessed. * class Test * { * Test() {} * public: * static OFoptional instance(); * . * . * . * }; * * // Override OFoptional's behavior to fix this problem * template<> * struct OFoptional_traits * : OFdefault_optional_traits // derived from default traits * { * // Tell OFoptional that it can't default-construct * // a Test object. * typedef OFfalse_type is_default_constructible; * }; * @endcode */ template class OFdefault_optional_traits { #ifndef DOXYGEN // types for detecting T's default constructibility via sfinae struct no_type {}; struct yes_type {double d;}; #ifdef HAVE_DEFAULT_CONSTRUCTOR_DETECTION_VIA_SFINAE // helper class to create an argument out of size_t template struct consume{}; // sfinae overload working for default constructible Xs template static yes_type sfinae(consume*); #elif defined(_MSC_VER) #if _MSC_VER < 1700 // Workaround bug in Visual Studio. // On these broken compilers, the argument is not evaluated // unless we require them to evaluate it for choosing which // specialization should be instantiated. template struct consume{}; template struct consume { typedef void type; }; // sfinae overload working for value-initializable Xs, that's as // close as we get on these broken compilers template static yes_type sfinae(typename consume::type*); #else // Visual Studio 2012 is completely broken, but it has std::is_default_constructible // Note: this tests constructibility, but not if WE can construct this. template static yes_type sfinae(typename OFenable_if::value>::type*); #endif // _MSC_VER #endif // HAVE_DEFAULT_CONSTRUCTOR_DETECTION_VIA_SFINAE // most general sfinae overload, chosen only if everything else fails template static no_type sfinae(...); public: struct is_default_constructible : OFintegral_constant(OFnullptr)) == sizeof(yes_type)> {}; #ifdef DCMTK_USE_CXX11_STL template void construct( Args&&... args ) { new (content()) T( std::forward( args )... ); m_State = OFTrue; } #else // C++11 #ifdef OFalign void construct() { new (content()) T; m_State = OFTrue; } template void construct( const X& x ) { new (content()) T( x ); m_State = OFTrue; } #else void construct() { m_pContent = new T; } template void construct( const X& x ) { m_pContent = new T( x ); } #endif #endif // NOT C++11 #ifdef OFalign // State and content are stored in the same data-array to // optimize alignment and so on. Mutable, since the content // itself can be modified even if it cant be (re-)assigned. OFdefault_optional_traits() : m_State( OFFalse ) {} void destroy() { OFstatic_cast( T*, content() )->~T(); m_State = OFFalse; } OFBool state() const { return m_State; } void* content() const { return m_Content; } mutable OFalign_typename(Uint8[sizeof(T)],T) m_Content; OFBool m_State; #else // Allocate content on the heap. OFdefault_optional_traits() : m_pContent( OFnullptr ) {} void destroy() { delete m_pContent; m_pContent = OFnullptr; } OFBool state() const { return m_pContent; } void* content() const { return m_pContent; } T* m_pContent; #endif #endif // NOT DOXYGEN }; /** Manages storage and state of the object contained in OFoptional. * OFoptional_traits is a customization point for OFoptional that enables you to define a custom storage management policy for * individual types T. If you don't want to implement everything from scratch, use OFdefault_optional_traits as base class for * your implementation. * @relates OFoptional * @tparam the content type of the respective OFoptional instance. * @sa OFoptional * @sa OFdefault_optional_traits * @details *

Example

* The following example shows how to implement custom OFoptional_traits for an enum that already contains a specific element * to denote an invalid state. * @code * enum FILE_ACCESS * { * NONE = 0000, * READ = 0400, * WRITE = 0200, * . . . * INVALID_ACCESS_CODE = 01000 * }; * * template<> * struct OFoptional_traits * { * // Tell OFoptional that this is default-constructible * typedef OFtrue_type is_default_constructible; * // Initialize storage to the invalid state during construction * OFoptional_traits() : access( INVALID_ACCESS_CODE ) {} * // Constructors * void construct() { access = NONE; } * void construct( FILE_ACCESS fa ) { access = fa; } * // There is nothing to destroy, just set the state to "disengaged" * void destroy() { access = INVALID_ACCESS_CODE; } * // Tell OFoptional how to distinguish "engaged" and "disengaged" FILE_ACCESS objects * OFBool state() const { return access != INVALID_ACCESS_CODE; } * // Just return a pointer to the underlying object * void* content() const { return &access; } * // The actual object * mutable FILE_ACCESS access; * }; * * COUT << "This should now be the same: " << sizeof( FILE_ACCESS ) << ' ' << sizeof( OFoptional ) << OFendl; * @endcode */ template struct OFoptional_traits #ifndef DOXYGEN : OFdefault_optional_traits #endif { #ifdef DOXYGEN /** Required: default construction policy. * You need to define an appropriate integral constant as "is_default_constructible" * that denotes if OFoptional may attempt to default construct the underlying object * under certain circumstances. You may use OFdefault_optional_traits::is_default_constructible * to specify this member, which uses SFINAE mechanisms to query a type's default constructibility. */ is_default_constructible; /// Requried: default constructor, must initialize the state to "disengaged". OFoptional_traits(); /** Required: type constructors, construct the contained object. * You need to define at least one method of this kind, that takes appropriate * parameter(s) to construct the underlying object. Must set the state to "engaged". * If is_default_constructible evaluates to OFTrue, an overload * taking zero arguments is also required. */ void construct(...); /// Required: type destructor, destroys the underlying object and must set the state to "disengaged". void destroy(); /// Required: state query, must return OFTrue when "engaged" and OFFalse otherwhise. OFBool state() const; /// Required: content access, must return a pointer to the contained object. void* content() const; #endif }; /** The class template OFoptional manages an optional contained value, i.e.\ a value tagged with a state that reports its validity. * A common use case for OFoptional is the return value of a function that may fail. OFoptional handles expensive to construct * objects well and is more readable, as the intent is expressed explicitly. * An OFoptional object which actually contains a value is called 'engaged', whereas an OFoptional object not containing a valid * value is called 'disengaged'. The global constant 'OFnullopt' of type 'OFnullopt_t' may be used to explicitly mark an optional * object as disengaged, for example to return a disengaged object from a function if an error occurred. * @tparam T the type of the value to manage initialization state for. The type's destructor must be accessible by OFoptional. * @note There exists a sufficient specialization for reference types (T&) that behaves exactly like a pointer (T*) but allows * OFoptional to be used in a generic context (when it's unknown if T is a reference or not). * @sa OFoptional_traits * @sa OFdefault_optional_traits * @details *

@anchor optional_syntax %OFoptional Syntax

* OFoptional can be used like a pointer to the contained value, except OFoptional also manages the contained value's storage. * Several operators have been overloaded to simplify the usage of OFoptional. Instead of looking at every overload's specification, * it is more appropriate to describe the possible syntax in a general manner. Therefore we declare the following symbols that are * used below to describe OFoptional's syntax and behavior: * * * * * * * * * * * * * * * * * * * * * * * * * * *
SymbolDefinition
T
The content type to be used
t
An object of type T
o, lhs, rhs
An object of type OFoptional
os
An STL compatible output stream
is
An STL compatible input stream
x
* May be: * - an object of type T * - an object of type OFoptional * - OFnullopt *
* The following table describes possible operations on OFoptional and related objects: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ExpressionMeaning
os << o
Prints content of o to os. Prints nullopt if o is disengaged.
is >> o
* Reads the content of o from is. * If the content cannot be read from is, o becomes disengaged.
* If o is disengaged before the expression is evaluated, the content of o is default * constructed unless T is not default constructible or T's default constructor is * not accessible by OFoptional. If default construction is not possible, the expression has * no effect (o remains disengaged). * @note Detecting if T is default constructible within OFoptional does not work correctly on all * compilers. Especially all versions of Microsoft Visual Studio are impaired. For example a private * default constructor of T might be detected as not accessible although OFoptional * was declared a friend of T. Specialize OFoptional_traits for a particular type T to * override constructibility detection as required. See @ref ofoptional_trait_override "this example". *
o == x, x == o
o != x, x != o
* - If x is an object of type T and o is engaged, x is compared to the content of o * in the appropriate fashion. Otherwise o is considered inequal to x. * - If x is another OFoptional object, the two objects are considered equal IFF both objects are * disengaged or both objects are engaged and their contents are equal. * - If x is OFnullopt, x and o are considered equal IFF o is disengaged. *
o < x, x > o
o > x, x < o
o <= x, x >= o
o >= x, x <= o
* - If x is an object of type T, x is compared to the content of o if o is engaged. * Otherwise o is considered less than x. * - If x is another OFoptional object, the state of both objects is compared whereas disengaged * is considered less than engaged. If both objects are engaged, their contents are compared to evaluate * the expression. * - If x is OFnullopt, o is considered equal to x if o is disengaged and * greater than x otherwise. *
* OFoptional o
* OFoptional o(x)
* OFoptional o(x0,...,xn)C++11
* OFmake_optional(t) *
* Construct an OFoptional object. The content type T must be specified explicitly unless OFmake_optional * is used, which deduces an appropriate type for T from the given parameter t.
* If C++11 support is available, OFoptional can be move constructed from x, allowing the content to be moved * into o instead of being copied. C++11 support also enables in-place construction of o, copying or * moving the given arguments as appropriate to construct o's content in the most efficient way. *
!o
Evaluates to OFTrue if o is disengaged, evaluates to OFFalse otherwise.
if(o), while(o), ...
* When used in an appropriate context, o is evaluated to OFTrue if o is * engaged and to OFFalse if o is disengaged.
* If C++11 support is available, the conversion operator is marked as explicit, which prevents * o to be interpreted as a boolean value in an inappropriate context. You should therefore use * o with caution when C++11 support is unavailable, as o might be converted to a boolean value * automatically where it shouldn't. *
*o
o.value()
* Access the content of o. The expression evaluates to a reference to o's content if o * is engaged. Otherwise the results are undefined. *
o.value_or(t)
* Access the content of o. The expression evaluates to a copy of o's content if o * is engaged. Otherwise a copy of t is returned.
* If C++11 support is available, t may be moved instead of being copied, if possible. *
o->
* Access a member of o's content. Members of compound data-types can be accessed via this syntax if o * is engaged. Otherwise the results are undefined. *
* o = x
* o.emplace(x0,...,xn)C++11 *
* Assign x to o. If x is another OFoptional object, the state is copied from x and * the content is only assigned if x is engaged. If x is OFnullopt o simply becomes disengaged.
* If C++11 support is available, OFoptional can be move assigned from x, allowing the content to be moved * into o instead of being copied. C++11 support also enables in-place assignment of o via the member * method emplace, copying or moving the given arguments as appropriate to assign o's content in the most * efficient way. *
o.swap(rhs)
OFswap(lhs, rhs)
* Swap state and contents of two OFoptional objects. * - Does nothing if both objects are disengaged. * - Calls OFswap(*o, *rhs) resp. OFswap(*lhs, *rhs) if both objects are engaged. * - Swaps the states if both objects' states differ and assigns the content of the engaged object * to the previously disengaged object. If C++11 support is available, the content is moved * from one object to the other. Otherwise the content is copied and afterwards destroyed in the now * disengaged object. *
* @note OFoptional is implemented based on the C++14 proposal for std::optional * [N3690, p. 503ff](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf) and is similar to * [Boost.Optional](http://www.boost.org/doc/libs/release/libs/optional/doc/html/index.html). * @details *

Usage example:

* @code{.cpp} * OFoptional my_atoi( const char* str ) * { * int result; * return parseValue( result, str ) ? OFoptional( result ) : OFnullopt; * } * * // Classical atoi, can't distinguish '0' from an error. * int i = atoi( "0" ); * if( !i ) // ERROR * * // Using OFoptional to distinguish '0' and parser error. * OFoptional i = my_atoi( "0" ); * if( !i ) // OK * { * // read optional value from standard input. * COUT << "Invalid value, please input a new value: "; * CIN >> i; * // if the user entered garbage, use 42 as default. * i = i.value_or( 42 ); * } * * // modify content of optional value and print the result. * *i += 3; * COUT << i << OFendl; * @endcode */ template class OFoptional #ifndef DOXYGEN : OFoptional_traits #endif { #ifndef DOXYGEN // create a matching istream type if condition is OFTrue template struct if_istream{ typedef STD_NAMESPACE basic_istream& type; }; // otherwise don't template struct if_istream {}; // use sfinae etc. to enable / disable the respective istream operator overloads template struct if_constructible : if_istream::is_default_constructible::value> {}; template struct if_not_constructible : if_istream::is_default_constructible::value> {}; public: // generic output stream operator overload template friend STD_NAMESPACE basic_ostream& operator<<( STD_NAMESPACE basic_ostream& os, const OFoptional& opt ) { if( opt ) return os << *opt; else return os << "nullopt"; } // input stream operator overload for default constructible Ts template friend typename if_constructible::type operator>>( STD_NAMESPACE basic_istream& is, OFoptional& opt ) { if( !opt ) { opt.construct(); if( (is >> *opt).fail() ) opt = OFnullopt; return is; } return is >> *opt; } // input stream operator overload for non default constructible Ts template friend typename if_not_constructible::type operator>>( STD_NAMESPACE basic_istream& is, OFoptional& opt ) { if( opt ) is >> *opt; return is; } // comparison operator overloads, see expression itself for details template friend OFTypename OFenable_if::value,bool>::type operator==( OFnullopt_t, const O& rhs ) { return !rhs; } template friend OFTypename OFenable_if::value,bool>::type operator==( const X& lhs, const O& rhs ) { return rhs.state() && lhs == *rhs; } template friend typename OFenable_if::value,bool>::type operator!=( OFnullopt_t, const O& rhs ) { return rhs.state(); } template friend OFTypename OFenable_if::value,bool>::type operator!=( const X& lhs, const O& rhs ) { return !rhs || lhs != *rhs; } template friend typename OFenable_if::value,bool>::type operator<( OFnullopt_t, const O& rhs ) { return rhs.state(); } template friend OFTypename OFenable_if::value,bool>::type operator<( const X& lhs, const O& rhs ) { return rhs.state() && lhs < *rhs; } template friend typename OFenable_if::value,bool>::type operator>( OFnullopt_t, const O& rhs ) { return OFFalse; } template friend OFTypename OFenable_if::value,bool>::type operator>( const X& lhs, const O& rhs ) { return !rhs || lhs > *rhs; } template friend typename OFenable_if::value,bool>::type operator<=( OFnullopt_t, const O& rhs ) { return OFTrue; } template friend OFTypename OFenable_if::value,bool>::type operator<=( const X& lhs, const O& rhs ) { return rhs.state() && lhs <= *rhs; } template friend typename OFenable_if::value,bool>::type operator>=( OFnullopt_t, const O& rhs ) { return !rhs; } template friend OFTypename OFenable_if::value,bool>::type operator>=( const X& lhs, const O& rhs ) { return !rhs || lhs >= *rhs; } bool operator==( OFnullopt_t ) { return !*this; } bool operator==( const OFoptional& rhs ) { return ( !*this && !rhs ) || ( OFoptional_traits::state() == rhs.state() && **this == *rhs ); } template bool operator==( const X& rhs ) { return OFoptional_traits::state() && **this == rhs; } bool operator!=( OFnullopt_t ) { return OFoptional_traits::state(); } bool operator!=( const OFoptional& rhs ) { return OFoptional_traits::state() != rhs.state() || ( rhs.state() && **this != *rhs ); } template bool operator!=( const X& rhs ) { return !*this || **this != rhs; } bool operator<( OFnullopt_t ) { return OFFalse; } bool operator<( const OFoptional& rhs ) { return OFoptional_traits::state() < rhs.state() || ( rhs.state() && **this < *rhs ); } template bool operator<( const X& rhs ) { return !*this || **this < rhs; } bool operator>( OFnullopt_t ) { return OFoptional_traits::state(); } bool operator>( const OFoptional& rhs ) { return OFoptional_traits::state() > rhs.state() || ( OFoptional_traits::state() && **this > *rhs ); } template bool operator>( const X& rhs ) { return OFoptional_traits::state() && **this > rhs; } bool operator<=( OFnullopt_t ) { return !*this; } bool operator<=( const OFoptional& rhs ) { return !*this || ( rhs.state() && **this <= *rhs ); } template bool operator<=( const X& rhs ) { return !*this || **this <= rhs; } bool operator>=( OFnullopt_t ) { return OFTrue; } bool operator>=( const OFoptional& rhs ) { return !rhs || ( OFoptional_traits::state() && **this >= *rhs ); } template bool operator>=( const X& rhs ) { return OFoptional_traits::state() && **this >= rhs; } // Default construct an OFoptional object in the disengaged state. OFconstexpr OFoptional() : OFoptional_traits() { } // Explicitly construct a disengaged OFoptional object. OFconstexpr OFoptional( OFnullopt_t ) : OFoptional_traits() { } // False friend of the copy constructor, to prevent incorrect behavior // (internally calls the real copy constructor). OFoptional( OFoptional& rhs ) #ifdef DCMTK_USE_CXX11_STL // delegate constructor if possible : OFoptional( const_cast( rhs ) ) { } #else // C++11 : OFoptional_traits() { if( rhs.state() ) OFoptional_traits::construct( *rhs ); } #endif // NOT C++11 // Copy the engaged state from rhs and its contents if rhs is engaged. OFoptional( const OFoptional& rhs ) : OFoptional_traits() { if( rhs.state() ) OFoptional_traits::construct( *rhs ); } #ifdef DCMTK_USE_CXX11_STL // Move constructor, kills rhs if it was engaged before. OFoptional( OFoptional&& rhs ) : OFoptional_traits() { if( rhs.state() ) { OFoptional_traits::construct( std::move( *rhs ) ); rhs.destroy(); } } // Variadic constructor that emplaces the content template OFoptional( Args&&... args ) : OFoptional_traits() { OFoptional_traits::construct( std::forward( args )... ); } // Move assignment OFoptional& operator=( OFoptional&& rhs ) { // Prevent self-assignment if( &rhs != this ) { // if both objects are engaged, move content // and kill rhs if( OFoptional_traits::state() == rhs.state() ) { if( OFoptional_traits::state() ) { (**this) = std::move( *rhs ); rhs.destroy(); } } else if( OFoptional_traits::state() ) // suicide if engaged and rhs isn't { OFoptional_traits::destroy(); } else // if rhs is engaged and we aren't, swap states, move contents and kill rhs. { OFoptional_traits::construct( std::move( *rhs ) ); rhs.destroy(); } } return *this; } // emplace assignment template OFoptional& emplace( Args&&... args ) { // emplace construct if we are disengaged if( !OFoptional_traits::state() ) OFoptional_traits::construct( std::forward( args )... ); else (**this) = T( std::forward( args )... ); // only emplace new content return *this; } #else // C++11 // Construct an engaged OFoptional object containing a copy of x. template OFoptional( const X& x ) : OFoptional_traits() { OFoptional_traits::construct( x ); } #endif // NOT C++11 // Destroy the contained object if engaged, otherwise do nothing. ~OFoptional() { if( OFoptional_traits::state() ) OFoptional_traits::destroy(); } // False friend of the assignment operator to prevent wrong behavior // (internally calls the real assignment operator). OFoptional& operator=( OFoptional& rhs ) { return (*this) = const_cast( rhs ); } // copy assignment OFoptional& operator=( const OFoptional& rhs ) { // Prevent self-assignment if( &rhs != this ) { // if both objects are engaged, copy content if( OFoptional_traits::state() == rhs.state() ) { if( OFoptional_traits::state() ) (**this) = *rhs; } else if( OFoptional_traits::state() ) // suicide if engaged and rhs isn't { OFoptional_traits::destroy(); } else // if rhs is engaged and we aren't, copy-construct from rhs. { OFoptional_traits::construct( *rhs ); } } return *this; } // State and content accessing functions, see respective expression for details // declare cast operator as explicit, if possible #ifdef DCMTK_USE_CXX11_STL explicit #endif // C++11 operator OFBool() const { return OFoptional_traits::state(); } OFBool operator!() const { return !OFoptional_traits::state(); } T& operator*() const { return *OFstatic_cast( T*, OFoptional_traits::content() ); } T* operator->() const { return OFstatic_cast( T*, OFoptional_traits::content() ); } // Swap the contents with another OFoptional object. void swap( OFoptional& rhs ) { // if both objects are engaged, the contents are swapped. if( OFoptional_traits::state() == rhs.state() ) { if( OFoptional_traits::state() ) OFswap( **this, *rhs ); } else { // if we are engaged and rhs isn't, move assign // our contents to rhs. if( OFoptional_traits::state() ) { rhs.construct( OFmove( **this ) ); OFoptional_traits::destroy(); } else // else move assign rhs' contents to us { OFoptional_traits::construct( OFmove( *rhs ) ); rhs.destroy(); } } } #endif // NOT DOXYGEN }; #ifndef DOXYGEN // Specialization for references that behaves like a pointer template class OFoptional { public: // generic ostream operator overload template friend STD_NAMESPACE basic_ostream& operator<<( STD_NAMESPACE basic_ostream& os, const OFoptional& opt ) { if( opt ) return os << *opt; else return os << "nullopt"; } // generic istream operator overload since references aren't default constructible template friend STD_NAMESPACE basic_istream& operator>>( STD_NAMESPACE basic_istream& is, OFoptional& opt ) { if( opt ) is >> *opt; return is; } // constructors and assignment operators, pretty self-explanatory OFconstexpr OFoptional() : m_pT( OFnullptr ) { } OFconstexpr OFoptional( T& t ) : m_pT( &t ) { } OFconstexpr OFoptional( OFnullopt_t ) : m_pT( OFnullptr ) { } OFconstexpr OFoptional( T* t ) : m_pT( t ) { } OFoptional( const OFoptional& rhs ) : m_pT( rhs.m_pT ) { } OFoptional& operator=( const OFoptional& rhs ) { if( &rhs != this ) m_pT = rhs.m_pT; return *this; } // Move semantics if C++11 is supported #ifdef DCMTK_USE_CXX11_STL OFoptional( OFoptional&& rhs ) : m_pT( rhs.m_pT ) { rhs.m_pT = OFnullptr; } OFoptional& operator=( OFoptional&& rhs ) { if( &rhs != this ) { m_pT = rhs.m_pT; rhs.m_pT = OFnullptr; } return *this; } // Can't really emplace-construct a reference, so this is // just a duplicate of the normal assignment operator, // for convenience. OFoptional& emplace( T& t ) { m_pT = &t; return *this; } // Default destructor, to disable some warnings about pointer // data members. ~OFoptional() = default; #else // C++11 inline ~OFoptional() {} #endif // State and content accessing functions, see respective expression for details // declare cast operator as explicit, if possible #ifdef DCMTK_USE_CXX11_STL explicit #endif // C++11 operator bool() const { return m_pT; } bool operator !() const { return !m_pT; } T& operator*() const { return *m_pT; } T* operator->() const { return m_pT; } // Swap the pointer, what else? void swap( OFoptional& rhs ) { OFswap( m_pT, rhs.m_pT ); } private: // The pointer that behaves like a pointer... T* m_pT; }; // Move semantics and std::swap overload if C++11 is supported #ifdef DCMTK_USE_CXX11_STL template OFoptional::type> OFmake_optional( T&& t ) { return OFoptional::type>( std::forward( t ) ); } namespace std { template void swap( OFoptional& lhs, OFoptional& rhs ) { lhs.swap( rhs ); } } #else // C++11 template OFoptional::type> OFmake_optional( const T& t ) { return OFoptional::type>( t ); } template void OFswap( OFoptional& lhs, OFoptional& rhs ) { lhs.swap( rhs ); } #endif // NOT C++11 #endif // NOT DOXYGEN #endif // OFOPTION_H