//------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ # pragma once # include # include # include //------------------------------------------------------------------------------ struct nullopt_t { struct init {}; nullopt_t(init) {} }; const nullopt_t nullopt((nullopt_t::init())); template struct optional { private: typedef typename std::aligned_storage::value>::type storage_type; typedef void (optional::*bool_type)() const; void safe_bool() const { } public: optional(); optional(nullopt_t); optional(const optional& v); optional(optional&& v); optional(const T& v); optional(T&& v); ~optional(); operator bool_type() const; optional& operator=(nullopt_t); optional& operator=(const optional& other); optional& operator=(optional&& other); // The function does not participate in overload resolution unless std::is_same, T>::value is true template // optional& operator=(U&& value); optional& operator=(typename std::enable_if::type, T>::value, U>::type&& value); T* operator->(); const T* operator->() const; T& operator*(); const T& operator*() const; T& value(); const T& value() const; # if defined(_MSC_VER) && (_MSC_VER > 1600) template T value_or(U&& default_value) const &; template T value_or(U&& default_value) &&; # else T value_or(const T& default_value); T value_or(const T& default_value) const; # endif bool has_value() const; void swap(optional& other); private: T* value_ptr() { return reinterpret_cast< T*>(&_value); } const T* value_ptr() const { return reinterpret_cast(&_value); } T& value_ref() { return *value_ptr(); } const T& value_ref() const { return *value_ptr(); } bool _has_value; storage_type _value; # if defined(_DEBUG) const T& _preview; # endif }; //------------------------------------------------------------------------------ template inline optional::optional(): _has_value(false) # if defined(_DEBUG) ,_preview(value_ref()) # endif { } template inline optional::optional(nullopt_t): _has_value(false) # if defined(_DEBUG) , _preview(value_ref()) # endif { } template inline optional::optional(const optional& v): _has_value(v._has_value) # if defined(_DEBUG) , _preview(value_ref()) # endif { if (_has_value) new (value_ptr()) T(v.value_ref()); } template inline optional::optional(optional&& v): _has_value(v._has_value) # if defined(_DEBUG) , _preview(value_ref()) # endif { if (!_has_value) return; new (value_ptr()) T(std::move(v.value_ref())); v.value_ref().~T(); v._has_value = false; } template inline optional::optional(const T& v): _has_value(true) # if defined(_DEBUG) , _preview(value_ref()) # endif { new (value_ptr()) T(v); } template inline optional::optional(T&& v): _has_value(true) # if defined(_DEBUG) , _preview(value_ref()) # endif { new (value_ptr()) T(std::forward(v)); } template inline optional::~optional() { if (_has_value) value_ref().~T(); } template inline optional::operator bool_type() const { return _has_value ? &optional::safe_bool : nullptr; } template inline optional& optional::operator= (nullopt_t) { optional().swap(*this); _has_value = false; return *this; } template inline optional& optional::operator=(const optional& other) { optional(other).swap(*this); return *this; } template inline optional& optional::operator=(optional&& other) { optional(std::forward(other)).swap(*this); return *this; } template template inline optional& optional::operator=(typename std::enable_if::type, T>::value, U>::type&& value) { optional(value).swap(*this); return *this; } template inline T* optional::operator->() { assert(_has_value); return value_ptr(); } template inline const T* optional::operator->() const { assert(_has_value); return value_ptr(); } template inline T& optional::operator*() { assert(_has_value); return value_ref(); } template inline const T& optional::operator*() const { assert(_has_value); return value_ref(); } template inline T& optional::value() { assert(_has_value); return value_ref(); } template inline const T& optional::value() const { assert(_has_value); return value_ref(); } # if defined(_MSC_VER) && (_MSC_VER > 1600) template template inline T optional::value_or(U&& default_value) const & { return bool(*this) ? value_ref() : static_cast(std::forward(default_value)); } template template inline T optional::value_or(U&& default_value) && { return bool(*this) ? std::move(value_ref()) : static_cast(std::forward(default_value)); } # else template T optional::value_or(const T& default_value) { return _has_value ? value_ref() : default_value; } template T optional::value_or(const T& default_value) const { return _has_value ? value_ref() : default_value; } # endif template inline bool optional::has_value() const { return _has_value; } template inline void optional::swap(optional& other) { using std::swap; if (_has_value && other._has_value) { swap(value_ref(), other.value_ref()); } else if (_has_value && !other._has_value) { new (other.value_ptr()) T(std::forward(value_ref())); value_ref().~T(); _has_value = false; other._has_value = true; } else if (!_has_value && other._has_value) { new (value_ptr()) T(std::forward(other.value_ref())); other.value_ref().~T(); _has_value = true; other._has_value = false; } } //------------------------------------------------------------------------------ template optional make_optional(T&& v) { return optional(std::forward(v)); } template inline void swap(optional& lhs, optional& rhs) { lhs.swap(rhs); } template inline bool operator==(const optional& lhs, const optional& rhs) { if (static_cast(lhs) != static_cast(rhs)) return false; if (!static_cast(lhs)) return true; return *lhs == *rhs; } template bool operator!=(const optional& lhs, const optional& rhs) { return !(lhs == rhs); } template inline bool operator<(const optional& lhs, const optional& rhs) { if (!static_cast(rhs)) return false; if (!static_cast(lhs)) return true; return *lhs < *rhs; } template inline bool operator>(const optional& lhs, const optional& rhs) { return rhs < lhs; } template inline bool operator<=(const optional& lhs, const optional& rhs) { return !(rhs < lhs); } template inline bool operator>=(const optional& lhs, const optional& rhs) { return !(lhs < rhs); } template inline bool operator==(const optional& opt, nullopt_t) { return !static_cast(opt); } template inline bool operator==(nullopt_t, const optional& opt) { return static_cast(opt); } template inline bool operator!=(const optional& opt, nullopt_t) { return static_cast(opt); } template inline bool operator!=(nullopt_t, const optional& opt) { return !static_cast(opt); } template inline bool operator<(const optional& opt, nullopt_t) { return false; } template inline bool operator<(nullopt_t, const optional& opt) { return static_cast(opt); } template inline bool operator<=(const optional& opt, nullopt_t) { return !opt; } template inline bool operator<=(nullopt_t, const optional& opt) { return true; } template inline bool operator>(const optional& opt, nullopt_t) { return static_cast(opt); } template inline bool operator>(nullopt_t, const optional& opt) { return false; } template inline bool operator>=(const optional&, nullopt_t) { return true; } template inline bool operator>=(nullopt_t, const optional& opt) { return !opt; } template inline bool operator==(const optional& opt, const T& v) { return static_cast(opt) ? *opt == v : false; } template inline bool operator==(const T& v, const optional& opt) { return static_cast(opt) ? *opt == v : false; } template inline bool operator!=(const optional& opt, const T& v) { return static_cast(opt) ? *opt != v : true; } template inline bool operator!=(const T& v, const optional& opt) { return static_cast(opt) ? *opt != v : true; } template inline bool operator<(const optional& opt, const T& v) { using namespace std; return static_cast(opt) ? less(*opt, v) : true; } template inline bool operator<(const T& v, const optional& opt) { using namespace std; return static_cast(opt) ? less(v, *opt) : false; } template inline bool operator<=(const optional& opt, const T& v) { using namespace std; return static_cast(opt) ? less_equal(*opt, v) : true; } template inline bool operator<=(const T& v, const optional& opt) { using namespace std; return static_cast(opt) ? less_equal(v, *opt) : false; } template inline bool operator>(const optional& opt, const T& v) { using namespace std; return static_cast(opt) ? greater(*opt, v) : false; } template inline bool operator>(const T& v, const optional& opt) { using namespace std; return static_cast(opt) ? greater(v, *opt) : true; } template inline bool operator>=(const optional& opt, const T& v) { using namespace std; return static_cast(opt) ? greater_equal(*opt, v) : false; } template inline bool operator>=(const T& v, const optional& opt) { using namespace std; return static_cast(opt) ? greater_equal(v, *opt) : true; }