#include <iostream>
#include <string>
#include <exception>
#include <type_traits>
namespace std
{
class bad_optional_access : public std::exception
{
public:
////////////////////////////////////////////////////////////////////////////////////////////
// Type definition
bad_optional_access() = default;
bad_optional_access(const bad_optional_access& that) = default;
virtual ~bad_optional_access() = default;
////////////////////////////////////////////////////////////////////////////////////////////
// Public methods
bad_optional_access& operator=(const bad_optional_access& that) = default;
virtual const char* what() const noexcept { return "bad optional access"; };
};
template <typename Type>
class optional
{
public:
static_assert(!std::is_reference<Type>::value, "Optional type can't be reference");
static_assert(!std::is_array<Type>::value, "Optional type can't be array");
////////////////////////////////////////////////////////////////////////////////////////////
// Type definition
using value_type = Type;
template <typename OtherType>
using compatible_t = std::enable_if_t<std::is_constructible<Type, std::remove_cv_t<OtherType>&&>::value, std::remove_cv_t<OtherType>>;
////////////////////////////////////////////////////////////////////////////////////////////
// Construction/destruction
optional() = default;
optional(const optional& that);
optional(optional&& that) noexcept;
template <typename OtherType = Type>
optional(OtherType&& value, std::decay_t<compatible_t<OtherType>>* ptr = nullptr) noexcept;
~optional() noexcept;
////////////////////////////////////////////////////////////////////////////////////////////
// Public methods
void swap(optional& that) noexcept;
optional& operator=(optional that) noexcept;
template <typename OtherType = Type>
optional& operator=(OtherType&& value) noexcept;
const Type* operator->() const;
Type* operator->();
const Type& operator*() const;
Type& operator*();
bool has_value() const noexcept;
explicit operator bool() const noexcept;
Type& value();
const Type& value() const;
template <typename Compatible = Type>
Type value_or(Compatible&& defValue) const;
void reset() noexcept;
private:
////////////////////////////////////////////////////////////////////////////////////////////
// Data member
typename std::aligned_storage<sizeof(Type), __alignof(Type)>::type m_data;
bool m_hasValue = false;
};
////////////////////////////////////////////////////////////////////////////////////////////////
// Optional comparison operators (declaration)
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
bool operator==(const optional<Type>& left, const optional<Type>& right);
template <typename Type, typename Compatible>
bool operator==(const optional<Type>& left, const Compatible& right);
template <typename Type, typename Compatible>
bool operator==(const Compatible& left, const optional<Type>& right);
template <typename Type>
bool operator!=(const optional<Type>& left, const optional<Type>& right);
template <typename Type, typename Compatible>
bool operator!=(const optional<Type>& left, const Compatible& right);
template <typename Type, typename Compatible>
bool operator!=(const Compatible& left, const optional<Type>& right);
template <typename Type>
bool operator<(const optional<Type>& left, const optional<Type>& right);
template <typename Type, typename Compatible>
bool operator<(const optional<Type>& left, const Compatible& right);
template <typename Type, typename Compatible>
bool operator<(const Compatible& left, const optional<Type>& right);
template <typename Type>
bool operator>(const optional<Type>& left, const optional<Type>& right);
template <typename Type, typename Compatible>
bool operator>(const optional<Type>& left, const Compatible& right);
template <typename Type, typename Compatible>
bool operator>(const Compatible& left, const optional<Type>& right);
////////////////////////////////////////////////////////////////////////////////////////////////
// class optional (implementation)
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Construction/destruction
template <typename Type>
inline optional<Type>::optional(const optional& that)
{
if (that.has_value())
new(this) optional(*that);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline optional<Type>::optional(optional&& that) noexcept
{
if (that.has_value()) {
new(this) optional(std::move(*that));
that.~optional();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
template <typename OtherType>
inline optional<Type>::optional(OtherType&& value, std::decay_t<compatible_t<OtherType>>*) noexcept
{
new(&m_data) Type(std::forward<OtherType>(value));
m_hasValue = true;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline optional<Type>::~optional() noexcept
{
if (has_value()) {
reinterpret_cast<Type&>(m_data).~Type();
m_hasValue = false;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Public methods
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline void optional<Type>::swap(optional& that) noexcept
{
using std::swap;
if (has_value() && that.has_value())
swap(*(*this), *that);
else if (has_value() && !that.has_value())
new(&that) optional(std::move(*this));
else if (!has_value() && that.has_value())
new(this) optional(std::move(that));
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline optional<Type>& optional<Type>::operator=(optional that) noexcept
{
swap(that);
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
template <typename OtherType>
inline optional<Type>& optional<Type>::operator=(OtherType&& value) noexcept
{
optional(std::move(value)).swap(*this);
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline const Type* optional<Type>::operator->() const
{
return reinterpret_cast<const Type*>(&m_data);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline Type* optional<Type>::operator->()
{
return reinterpret_cast<Type*>(&m_data);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline const Type& optional<Type>::operator*() const
{
return reinterpret_cast<const Type&>(m_data);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline Type& optional<Type>::operator*()
{
return reinterpret_cast<Type&>(m_data);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline bool optional<Type>::has_value() const noexcept
{
return m_hasValue;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline optional<Type>::operator bool() const noexcept
{
return has_value();
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline Type& optional<Type>::value()
{
if (!has_value())
throw bad_optional_access();
return *(*this);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline const Type& optional<Type>::value() const
{
if (!has_value())
throw bad_optional_access();
return *(*this);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
template <typename Compatible>
inline Type optional<Type>::value_or(Compatible&& defValue) const
{
if (!has_value())
return static_cast<Type>(std::forward<Compatible>(defValue));
return *(*this);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline void optional<Type>::reset() noexcept
{
optional().swap(*this);
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Optional comparison operators (implementation)
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline bool operator==(const optional<Type>& left, const optional<Type>& right)
{
if (left.has_value() != right.has_value())
return false;
if (!left.has_value())
return true;
return *left == *right;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type, typename Compatible>
inline bool operator==(const optional<Type>& left, const Compatible& right)
{
if (!left.has_value())
return false;
return *left == right;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type, typename Compatible>
inline bool operator==(const Compatible& left, const optional<Type>& right)
{
if (!right.has_value())
return false;
return left == *right;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline bool operator!=(const optional<Type>& left, const optional<Type>& right)
{
return !operator==(left, right);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type, typename Compatible>
inline bool operator!=(const optional<Type>& left, const Compatible& right)
{
return !operator==(left, right);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type, typename Compatible>
inline bool operator!=(const Compatible& left, const optional<Type>& right)
{
return !operator==(left, right);
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline bool operator<(const optional<Type>& left, const optional<Type>& right)
{
if (left.has_value() && !right.has_value())
return false;
if (!left.has_value() && right.has_value())
return true;
if (left.has_value())
return *left < *right;
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type, typename Compatible>
inline bool operator<(const optional<Type>& left, const Compatible& right)
{
if (!left.has_value())
return true;
return *left < right;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type, typename Compatible>
inline bool operator<(const Compatible& left, const optional<Type>& right)
{
if (!right.has_value())
return false;
return left < *right;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type>
inline bool operator>(const optional<Type>& left, const optional<Type>& right)
{
return right < left;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type, typename Compatible>
inline bool operator>(const optional<Type>& left, const Compatible& right)
{
return right < left;
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Type, typename Compatible>
inline bool operator>(const Compatible& left, const optional<Type>& right)
{
return right < left;
}
} // namespace std
struct SomeClass {};
struct Container
{
Container() = default;
explicit Container(int) {}
explicit Container(double) {}
explicit Container(const std::string&) {}
explicit Container(const SomeClass&) {}
explicit Container(const std::optional<SomeClass>&) {}
explicit operator int () const {return {}; }
explicit operator double () const {return {}; }
explicit operator std::string () const {return {}; }
explicit operator SomeClass () const {return {}; }
explicit operator std::optional<SomeClass> () const {return {}; }
};
////////////////////////////////////////////////////////////////////////////////
// Test
////////////////////////////////////////////////////////////////////////////////
const Container cont1(int{});
const Container cont2(double{});
const Container cont3(std::string{});
const Container cont4(SomeClass{});
const Container cont5(std::optional<SomeClass>{});
const double v1(cont1);
const int v2(cont2);
const std::string v3(cont3);
const SomeClass v4(cont4);
const std::optional<int> v5(cont5);
int main() {
std::optional<int> opt = 1234;
std::optional<int> optCopy;
optCopy = opt;
std::cout << optCopy.value();
}