#pragma once #include #include #include struct in_place_t { explicit in_place_t() = default; }; template class optional { using Storage = typename std::aligned_storage::value>::type; Storage m_storage; bool m_valid = false; public: typedef optional self_type; optional() = default; ~optional() { reset(); } optional(const optional& src) : m_valid(src.m_valid) { if (src.m_valid) { new(&m_storage) BaseType(*src); } } optional(optional&& src) : m_valid(src.m_valid) { if (src.m_valid) { new(&m_storage) BaseType(std::move(*src)); } } template::value && !(std::is_same::type, self_type>::value) >::type > optional(U&& value) : m_valid(true) { new(&m_storage) BaseType(std::forward(value)); } template::value>::type> explicit optional(in_place_t tag, Args&&... args) : m_valid(true) { new(&m_storage) BaseType(std::forward(args)...); } optional& operator = (optional&& src) noexcept { if (src.m_valid) { if (m_valid) { **this = std::move(*src); } else { new(&m_storage) BaseType(std::move(*src)); m_valid = true; } } else if (m_valid) { reinterpret_cast(&m_storage)->~BaseType(); m_valid = false; } return *this; } optional& operator = (const optional& src) { if (src.m_valid) { if (m_valid) { **this = *src; } else { new(&m_storage) BaseType(*src); m_valid = true; } } else if (m_valid) { reinterpret_cast(&m_storage)->~BaseType(); m_valid = false; } return *this; } template::type, self_type>::value && std::is_constructible::value && std::is_assignable::value >::type> optional& operator = (U&& value) { if (m_valid) { **this = std::forward(value); } else { new(&m_storage) BaseType(std::forward(value)); m_valid = true; } return *this; } void reset() { if (m_valid) { (**this).BaseType::~BaseType(); m_valid = false; } } constexpr explicit operator bool() const { return m_valid; } constexpr bool has_value() const { return m_valid; } constexpr bool valid() const { return has_value(); } BaseType& operator * () & { assert(m_valid); return *reinterpret_cast(&m_storage); } const BaseType& operator * () const & { assert(m_valid); return *reinterpret_cast(&m_storage); } BaseType&& operator * () && { assert(m_valid); return std::move(*reinterpret_cast(&m_storage)); } const BaseType&& operator * () const && { assert(m_valid); return std::move(*reinterpret_cast(&m_storage)); } BaseType* operator -> () { assert(m_valid); return reinterpret_cast(&m_storage); } const BaseType* operator -> () const { assert(m_valid); return reinterpret_cast(&m_storage); } BaseType& value() { if (!has_value()) { throw std::logic_error("bad_optional_access"); } return **this; } const BaseType& value() const { if (!has_value()) { throw std::logic_error("bad_optional_access"); } return **this; } template BaseType value_or(U&& default_value) && { return has_value() ? std::move(**this) : static_cast(std::forward(default_value)); } template const BaseType value_or(U&& default_value) const & { return has_value() ? **this : static_cast(std::forward(default_value)); } template BaseType& emplace(Args&&... args) { reset(); new(&m_storage) BaseType(std::forward(args)...); m_valid = true; return **this; } }; template optional::type> make_optional(T&& val) { return optional::type>(std::forward(val)); } template optional make_optional(Args&&... args) { return optional(in_place_t{}, std::forward(args)...); }