dlib C++ Library - optional.h

// Copyright (C) 2023 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_OPTIONAL_H
#define DLIB_OPTIONAL_H
#include <exception>
#include <initializer_list>
#include "functional.h"
namespace dlib
{
// ---------------------------------------------------------------------------------------------------
 class bad_optional_access : public std::exception 
 {
 public:
 bad_optional_access() = default;
 const char *what() const noexcept { return "Optional has no value"; }
 };
// ---------------------------------------------------------------------------------------------------
 struct nullopt_t 
 {
 nullopt_t() = delete;
 constexpr explicit nullopt_t(int) noexcept {}
 };
 static constexpr nullopt_t nullopt{int{}};
// ---------------------------------------------------------------------------------------------------
 template<class T>
 class optional;
 /*!
 WHAT THIS OBJECT REPRESENTS 
 This is a standard's compliant backport of std::optional that works with C++14.
 It includes C++23 monadic interfaces
 Therefore, refer to https://en.cppreference.com/w/cpp/utility/optional for docs on the
 interface of optional.
 !*/
// ---------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------
// IMPLEMENTATION DETAILS BELOW
// ---------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------
 namespace details
 {
 template<class T>
 struct is_optional : std::false_type{};
 template<class T>
 struct is_optional<dlib::optional<T>> : std::true_type{};
 template<class T, class U>
 using is_constructible_from = And<
 !std::is_constructible<T, dlib::optional<U>&>::value,
 !std::is_constructible<T, const dlib::optional<U>&>::value,
 !std::is_constructible<T, dlib::optional<U>&&>::value,
 !std::is_constructible<T, const dlib::optional<U>&&>::value,
 !std::is_convertible< dlib::optional<U>&, T>::value,
 !std::is_convertible<const dlib::optional<U>&, T>::value,
 !std::is_convertible< dlib::optional<U>&&, T>::value,
 !std::is_convertible<const dlib::optional<U>&&, T>::value
 >;
 template<class T, class U>
 using is_assignable_from = And<
 is_constructible_from<T,U>::value,
 std::is_assignable<T&, dlib::optional<U>&>::value,
 std::is_assignable<T&, const dlib::optional<U>&>::value,
 std::is_assignable<T&, dlib::optional<U>&&>::value,
 std::is_assignable<T&, const dlib::optional<U>&&>::value
 >;
 template<class T, class U>
 using is_copy_convertible = std::enable_if_t<
 is_constructible_from<T,U>::value &&
 std::is_constructible<T, const U&>::value,
 bool
 >;
 template<class T, class U>
 using is_move_convertible = std::enable_if_t<
 is_constructible_from<T,U>::value &&
 std::is_constructible<T, U&&>::value,
 bool
 >;
 template<class T, class U>
 using is_copy_assignable = std::enable_if_t<
 is_assignable_from<T,U>::value &&
 std::is_constructible<T, const U&>::value &&
 std::is_assignable<T&, const U&>::value,
 bool
 >;
 template<class T, class U>
 using is_move_assignable = std::enable_if_t<
 is_assignable_from<T,U>::value &&
 std::is_constructible<T, U>::value &&
 std::is_assignable<T&, U>::value,
 bool
 >;
 template<class T, class U, class U_ = std::decay_t<U>>
 using is_construct_convertible_from = std::enable_if_t<
 std::is_constructible<T, U&&>::value &&
 !std::is_same<U_, in_place_t>::value &&
 !std::is_same<U_, dlib::optional<T>>::value,
 bool
 >;
 template <class T, class U, class U_ = std::decay_t<U>>
 using is_assign_convertible_from = std::enable_if_t<
 std::is_constructible<T, U>::value && 
 std::is_assignable<T&, U>::value &&
 !std::is_same<U_, dlib::optional<T>>::value &&
 (!std::is_scalar<T>::value || !std::is_same<T, U_>::value),
 bool
 >;
// ---------------------------------------------------------------------------------------------------
 template <
 class T,
 bool = std::is_trivially_destructible<T>::value
 >
 struct optional_storage
 {
 constexpr optional_storage() noexcept
 : e{}, active{false}
 {}
 template<class ...U>
 constexpr optional_storage(in_place_t, U&& ...u) noexcept(std::is_nothrow_constructible<T,U...>::value)
 : val{std::forward<U>(u)...}, active{true} 
 {}
 ~optional_storage() noexcept(std::is_nothrow_destructible<T>::value)
 {
 if (active)
 val.~T();
 } 
 struct empty{};
 union {T val; empty e;};
 bool active{false};
 };
 template <class T>
 struct optional_storage<T, true>
 {
 constexpr optional_storage() noexcept
 : e{}, active{false}
 {}
 template<class ...U>
 constexpr optional_storage(in_place_t, U&& ...u) noexcept(std::is_nothrow_constructible<T,U...>::value)
 : val{std::forward<U>(u)...}, active{true} 
 {}
 struct empty{};
 union {T val; empty e;};
 bool active{false};
 };
// ---------------------------------------------------------------------------------------------------
 template <class T>
 struct optional_ops : optional_storage<T> 
 {
 using optional_storage<T>::optional_storage;
 template <class... U> 
 constexpr void construct(U&&... u) noexcept(std::is_nothrow_constructible<T,U...>::value)
 {
 new (std::addressof(this->val)) T(std::forward<U>(u)...);
 this->active = true;
 }
 template<class Optional>
 constexpr void assign(Optional&& rhs) noexcept(std::is_nothrow_constructible<T,Optional>::value &&
 std::is_nothrow_assignable<T&,Optional>::value)
 {
 if (this->active && rhs.active)
 this->val = std::forward<Optional>(rhs).val;
 else if (!this->active && rhs.active)
 construct(std::forward<Optional>(rhs).val);
 else if (this->active && !rhs.active)
 destruct();
 }
 constexpr void destruct() noexcept(std::is_nothrow_destructible<T>::value)
 {
 if (this->active)
 {
 this->val.~T();
 this->active = false;
 }
 }
 };
// ---------------------------------------------------------------------------------------------------
 template <class T, bool = std::is_trivially_copy_constructible<T>::value>
 struct optional_copy : optional_ops<T> 
 {
 using optional_ops<T>::optional_ops;
 };
 template <class T>
 struct optional_copy<T, false> : optional_ops<T> 
 {
 using optional_ops<T>::optional_ops;
 constexpr optional_copy() = default;
 constexpr optional_copy(optional_copy&& rhs) = default;
 constexpr optional_copy &operator=(const optional_copy& rhs) = default;
 constexpr optional_copy &operator=(optional_copy&& rhs) = default;
 constexpr optional_copy(const optional_copy& rhs) noexcept(std::is_nothrow_copy_constructible<T>::value)
 : optional_ops<T>() 
 {
 if (rhs.active)
 this->construct(rhs.val);
 }
 };
// ---------------------------------------------------------------------------------------------------
 template <class T, bool = std::is_trivially_move_constructible<T>::value>
 struct optional_move : optional_copy<T> 
 {
 using optional_copy<T>::optional_copy;
 };
 template <class T> 
 struct optional_move<T, false> : optional_copy<T> 
 {
 using optional_copy<T>::optional_copy;
 constexpr optional_move() = default;
 constexpr optional_move(const optional_move& rhs) = default;
 constexpr optional_move& operator=(const optional_move& rhs) = default;
 constexpr optional_move& operator=(optional_move&& rhs) = default;
 constexpr optional_move(optional_move&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value)
 {
 if (rhs.active)
 this->construct(std::move(rhs.val));
 }
 };
// ---------------------------------------------------------------------------------------------------
 template <
 class T, 
 bool = std::is_trivially_copy_assignable<T>::value &&
 std::is_trivially_copy_constructible<T>::value &&
 std::is_trivially_destructible<T>::value
 >
 struct optional_copy_assign : optional_move<T> 
 {
 using optional_move<T>::optional_move;
 };
 template <class T>
 struct optional_copy_assign<T, false> : optional_move<T> 
 {
 using optional_move<T>::optional_move;
 constexpr optional_copy_assign() = default;
 constexpr optional_copy_assign(const optional_copy_assign& rhs) = default;
 constexpr optional_copy_assign(optional_copy_assign&& rhs) = default;
 constexpr optional_copy_assign& operator=(optional_copy_assign &&rhs) = default;
 constexpr optional_copy_assign& operator=(const optional_copy_assign &rhs) 
 noexcept(std::is_nothrow_copy_constructible<T>::value && 
 std::is_nothrow_copy_assignable<T>::value)
 {
 this->assign(rhs);
 return *this;
 } 
 };
// ---------------------------------------------------------------------------------------------------
 template <
 class T, 
 bool = std::is_trivially_destructible<T>::value &&
 std::is_trivially_move_constructible<T>::value &&
 std::is_trivially_move_assignable<T>::value
 >
 struct optional_move_assign : optional_copy_assign<T> 
 {
 using optional_copy_assign<T>::optional_copy_assign;
 };
 template <class T>
 struct optional_move_assign<T, false> : optional_copy_assign<T> 
 {
 using optional_copy_assign<T>::optional_copy_assign;
 constexpr optional_move_assign() = default;
 constexpr optional_move_assign(const optional_move_assign &rhs) = default;
 constexpr optional_move_assign(optional_move_assign &&rhs) = default;
 constexpr optional_move_assign& operator=(const optional_move_assign &rhs) = default;
 constexpr optional_move_assign& operator=(optional_move_assign &&rhs) 
 noexcept(std::is_nothrow_move_constructible<T>::value && 
 std::is_nothrow_move_assignable<T>::value)
 {
 this->assign(std::move(rhs));
 return *this;
 }
 };
// ---------------------------------------------------------------------------------------------------
 template <
 class T, 
 bool copyable = std::is_copy_constructible<T>::value,
 bool moveable = std::is_move_constructible<T>::value
 >
 struct optional_delete_constructors
 {
 constexpr optional_delete_constructors() = default;
 constexpr optional_delete_constructors(const optional_delete_constructors&) = default;
 constexpr optional_delete_constructors(optional_delete_constructors&&) = default;
 constexpr optional_delete_constructors& operator=(const optional_delete_constructors &) = default;
 constexpr optional_delete_constructors& operator=(optional_delete_constructors &&) = default;
 };
 template <class T> 
 struct optional_delete_constructors<T, true, false> 
 {
 constexpr optional_delete_constructors() = default;
 constexpr optional_delete_constructors(const optional_delete_constructors&) = default;
 constexpr optional_delete_constructors(optional_delete_constructors&&) = delete;
 constexpr optional_delete_constructors& operator=(const optional_delete_constructors &) = default;
 constexpr optional_delete_constructors& operator=(optional_delete_constructors &&) = default;
 };
 template <class T> 
 struct optional_delete_constructors<T, false, true>
 {
 constexpr optional_delete_constructors() = default;
 constexpr optional_delete_constructors(const optional_delete_constructors&) = delete;
 constexpr optional_delete_constructors(optional_delete_constructors&&) = default;
 constexpr optional_delete_constructors& operator=(const optional_delete_constructors &) = default;
 constexpr optional_delete_constructors& operator=(optional_delete_constructors &&) = default;
 };
 template <class T> 
 struct optional_delete_constructors<T, false, false>
 {
 constexpr optional_delete_constructors() = default;
 constexpr optional_delete_constructors(const optional_delete_constructors&) = delete;
 constexpr optional_delete_constructors(optional_delete_constructors&&) = delete;
 constexpr optional_delete_constructors& operator=(const optional_delete_constructors&) = default;
 constexpr optional_delete_constructors& operator=(optional_delete_constructors &&) = default;
 };
// ---------------------------------------------------------------------------------------------------
 template <
 class T,
 bool copyable = (std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value),
 bool moveable = (std::is_move_constructible<T>::value && std::is_move_assignable<T>::value)
 >
 struct optional_delete_assign
 {
 constexpr optional_delete_assign() = default;
 constexpr optional_delete_assign(const optional_delete_assign &) = default;
 constexpr optional_delete_assign(optional_delete_assign &&) = default;
 constexpr optional_delete_assign& operator=(const optional_delete_assign &) = default;
 constexpr optional_delete_assign& operator=(optional_delete_assign &&) = default;
 };
 template <class T> 
 struct optional_delete_assign<T, true, false>
 {
 constexpr optional_delete_assign() = default;
 constexpr optional_delete_assign(const optional_delete_assign &) = default;
 constexpr optional_delete_assign(optional_delete_assign &&) = default;
 constexpr optional_delete_assign& operator=(const optional_delete_assign &) = default;
 constexpr optional_delete_assign& operator=(optional_delete_assign &&) = delete;
 };
 template <class T> 
 struct optional_delete_assign<T, false, true>
 {
 constexpr optional_delete_assign() = default;
 constexpr optional_delete_assign(const optional_delete_assign &) = default;
 constexpr optional_delete_assign(optional_delete_assign &&) = default;
 constexpr optional_delete_assign& operator=(const optional_delete_assign &) = delete;
 constexpr optional_delete_assign& operator=(optional_delete_assign &&) = default;
 };
 template <class T> 
 struct optional_delete_assign<T, false, false>
 {
 constexpr optional_delete_assign() = default;
 constexpr optional_delete_assign(const optional_delete_assign &) = default;
 constexpr optional_delete_assign(optional_delete_assign &&) = default;
 constexpr optional_delete_assign& operator=(const optional_delete_assign &) = delete;
 constexpr optional_delete_assign& operator=(optional_delete_assign &&) = delete;
 };
// ---------------------------------------------------------------------------------------------------
 }
// ---------------------------------------------------------------------------------------------------
 template <class T>
 class optional : private details::optional_move_assign<T>,
 private details::optional_delete_constructors<T>,
 private details::optional_delete_assign<T> 
 {
 using base = details::optional_move_assign<T>;
 static_assert(!std::is_reference<T>::value, "optional<T&> not allowed");
 static_assert(!std::is_same<T, in_place_t>::value, "optional<in_place_t> not allowed");
 static_assert(!std::is_same<T, nullopt_t>::value, "optional<nullopt_t> not allowed");
 public:
 using value_type = T;
 
 constexpr optional() = default;
 constexpr optional(const optional &rhs) = default;
 constexpr optional(optional &&rhs) = default;
 constexpr optional& operator=(const optional &rhs) = default;
 constexpr optional& operator=(optional &&rhs) = default;
 ~optional() = default;
 constexpr optional(nullopt_t) noexcept {}
 constexpr optional& operator=(nullopt_t) noexcept 
 {
 if (*this)
 reset();
 return *this;
 }
 template <
 class U, 
 details::is_copy_convertible<T,U> = true,
 std::enable_if_t<!std::is_convertible<const U&, T>::value, bool> = true
 >
 constexpr explicit optional(const optional<U> &rhs) noexcept(std::is_nothrow_constructible<T,const U&>::value)
 {
 if (rhs)
 this->construct(*rhs);
 }
 template <
 class U, 
 details::is_copy_convertible<T,U> = true,
 std::enable_if_t<std::is_convertible<const U&, T>::value, bool> = true
 >
 constexpr optional(const optional<U> &rhs) noexcept(std::is_nothrow_constructible<T,const U&>::value)
 {
 if (rhs)
 this->construct(*rhs);
 }
 template <
 class U, 
 details::is_move_convertible<T,U> = true,
 std::enable_if_t<!std::is_convertible<U&&, T>::value, bool> = true
 >
 constexpr explicit optional(optional<U>&& rhs) noexcept(std::is_nothrow_constructible<T,U&&>::value)
 {
 if (rhs)
 this->construct(std::move(*rhs));
 }
 template <
 class U, 
 details::is_move_convertible<T,U> = true,
 std::enable_if_t<std::is_convertible<U&&, T>::value, bool> = true
 >
 constexpr optional(optional<U>&& rhs) noexcept(std::is_nothrow_constructible<T,U&&>::value)
 {
 if (rhs)
 this->construct(std::move(*rhs));
 }
 template <
 class... Args,
 std::enable_if_t<std::is_constructible<T, Args...>::value, bool> = true
 >
 constexpr explicit optional (
 in_place_t,
 Args&&... args
 ) noexcept(std::is_nothrow_constructible<T,Args&&...>::value)
 : base(in_place, std::forward<Args>(args)...)
 {
 }
 template <
 class U, 
 class... Args,
 std::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, bool> = true
 >
 constexpr explicit optional (
 in_place_t,
 std::initializer_list<U> il,
 Args &&... args
 ) noexcept(std::is_nothrow_constructible<T,std::initializer_list<U>&,Args&&...>::value)
 {
 this->construct(il, std::forward<Args>(args)...);
 }
 template<
 class U,
 details::is_construct_convertible_from<T,U> = true,
 std::enable_if_t<!std::is_convertible<U&&, T>::value, bool> = true
 >
 constexpr explicit optional(U &&u) noexcept(std::is_nothrow_constructible<T, U&&>::value)
 : base(in_place, std::forward<U>(u))
 {
 }
 template<
 class U,
 details::is_construct_convertible_from<T,U> = true,
 std::enable_if_t<std::is_convertible<U&&, T>::value, bool> = true
 >
 constexpr optional(U &&u) noexcept(std::is_nothrow_constructible<T, U&&>::value)
 : base(in_place, std::forward<U>(u))
 {
 } 
 template <
 class U,
 details::is_copy_assignable<T, U> = true
 >
 constexpr optional &operator=(const optional<U>& rhs) noexcept(std::is_nothrow_constructible<T, const U&>::value &&
 std::is_nothrow_assignable<T, const U&>::value)
 {
 this->assign(rhs);
 return *this;
 }
 template <
 class U,
 details::is_move_assignable<T, U> = true
 >
 constexpr optional &operator=(optional<U>&& rhs) noexcept(std::is_nothrow_constructible<T, U>::value &&
 std::is_nothrow_assignable<T, U>::value)
 {
 this->assign(std::move(rhs));
 return *this;
 }
 
 template <
 class U, 
 details::is_assign_convertible_from<T,U> = true
 >
 constexpr optional& operator=(U &&u) noexcept(std::is_nothrow_constructible<T, U>::value &&
 std::is_nothrow_assignable<T, U>::value)
 {
 if (*this)
 **this = std::forward<U>(u);
 else
 this->construct(std::forward<U>(u));
 return *this;
 }
 template <class... Args> 
 constexpr T& emplace(Args &&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value)
 {
 reset();
 this->construct(std::forward<Args>(args)...);
 return **this;
 }
 template <class U, class... Args>
 constexpr T& emplace(std::initializer_list<U> il, Args &&... args) 
 {
 reset();
 this->construct(il, std::forward<Args>(args)...);
 return **this; 
 }
 void swap(optional& rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
 dlib::is_nothrow_swappable<T>::value) 
 {
 using std::swap;
 if (*this && rhs)
 {
 swap(**this, *rhs);
 }
 
 else if (*this && !rhs)
 {
 rhs = std::move(**this);
 reset();
 }
 
 else if (!*this && rhs)
 {
 *this = std::move(*rhs);
 rhs.reset();
 }
 }
 constexpr const T* operator->() const noexcept { return &this->val; }
 constexpr T* operator->() noexcept { return &this->val; }
 constexpr T& operator*() & noexcept { return this->val; }
 constexpr const T& operator*() const& noexcept { return this->val; }
 constexpr T&& operator*() && noexcept { return std::move(this->val); }
 constexpr const T&& operator*() const&& noexcept { return std::move(this->val); }
 constexpr explicit operator bool() const noexcept { return this->active; }
 constexpr bool has_value() const noexcept { return this->active; }
 constexpr T& value() & 
 {
 if (*this)
 return **this;
 throw bad_optional_access();
 }
 constexpr const T& value() const & 
 {
 if (*this)
 return **this;
 throw bad_optional_access();
 }
 constexpr T&& value() && 
 {
 if (*this)
 return std::move(**this);
 throw bad_optional_access();
 }
 constexpr const T&& value() const && 
 {
 if (*this)
 return std::move(**this);
 throw bad_optional_access();
 }
 template <class U> 
 constexpr T value_or(U &&u) const & 
 {
 return *this ? **this : static_cast<T>(std::forward<U>(u));
 }
 template <class U> 
 constexpr T value_or(U &&u) && 
 {
 return *this ? std::move(**this) : static_cast<T>(std::forward<U>(u));
 }
 void reset() noexcept(std::is_nothrow_destructible<T>::value)
 {
 this->destruct();
 }
 template <
 class F,
 class Return = dlib::remove_cvref_t<dlib::invoke_result_t<F,T&>>,
 std::enable_if_t<details::is_optional<Return>::value, bool> = true
 >
 constexpr auto and_then(F&& f) &
 {
 if (*this)
 return dlib::invoke(std::forward<F>(f), **this);
 else
 return Return{};
 }
 template <
 class F,
 class Return = dlib::remove_cvref_t<dlib::invoke_result_t<F,const T&>>,
 std::enable_if_t<details::is_optional<Return>::value, bool> = true
 >
 constexpr auto and_then(F&& f) const&
 {
 if (*this)
 return dlib::invoke(std::forward<F>(f), **this);
 else
 return Return{};
 }
 template <
 class F,
 class Return = dlib::remove_cvref_t<dlib::invoke_result_t<F,T>>,
 std::enable_if_t<details::is_optional<Return>::value, bool> = true
 >
 constexpr auto and_then(F&& f) &&
 {
 if (*this)
 return dlib::invoke(std::forward<F>(f), std::move(**this));
 else
 return Return{};
 }
 template <
 class F,
 class Return = dlib::remove_cvref_t<dlib::invoke_result_t<F,const T>>,
 std::enable_if_t<details::is_optional<Return>::value, bool> = true
 >
 constexpr auto and_then(F&& f) const&&
 {
 if (*this)
 return dlib::invoke(std::forward<F>(f), std::move(**this));
 else
 return Return{};
 }
 template <
 class F,
 class U = dlib::remove_cvref_t<dlib::invoke_result_t<F, T&>>,
 std::enable_if_t<!std::is_same<U, dlib::in_place_t>::value, bool> = true,
 std::enable_if_t<!std::is_same<U, dlib::nullopt_t>::value, bool> = true
 >
 constexpr dlib::optional<U> transform(F&& f) &
 {
 if (*this)
 return dlib::invoke(std::forward<F>(f), **this);
 else
 return dlib::optional<U>{};
 }
 template <
 class F,
 class U = dlib::remove_cvref_t<dlib::invoke_result_t<F, const T&>>,
 std::enable_if_t<!std::is_same<U, dlib::in_place_t>::value, bool> = true,
 std::enable_if_t<!std::is_same<U, dlib::nullopt_t>::value, bool> = true
 >
 constexpr dlib::optional<U> transform(F&& f) const&
 {
 if (*this)
 return dlib::invoke(std::forward<F>(f), **this);
 else
 return dlib::optional<U>{};
 }
 template <
 class F,
 class U = dlib::remove_cvref_t<dlib::invoke_result_t<F,T>>,
 std::enable_if_t<!std::is_same<U, dlib::in_place_t>::value, bool> = true,
 std::enable_if_t<!std::is_same<U, dlib::nullopt_t>::value, bool> = true
 >
 constexpr dlib::optional<U> transform(F&& f) &&
 {
 if (*this)
 return dlib::invoke(std::forward<F>(f), std::move(**this));
 else
 return dlib::optional<U>{};
 }
 template <
 class F,
 class U = dlib::remove_cvref_t<dlib::invoke_result_t<F,const T>>,
 std::enable_if_t<!std::is_same<U, dlib::in_place_t>::value, bool> = true,
 std::enable_if_t<!std::is_same<U, dlib::nullopt_t>::value, bool> = true
 >
 constexpr dlib::optional<U> transform(F&& f) const&&
 {
 if (*this)
 return dlib::invoke(std::forward<F>(f), std::move(**this));
 else
 return dlib::optional<U>{};
 }
 template < 
 class F,
 class U = dlib::remove_cvref_t<dlib::invoke_result_t<F>>,
 std::enable_if_t<std::is_same<U, dlib::optional<T>>::value, bool> = true
 >
 constexpr optional or_else( F&& f ) const&
 {
 return *this ? *this : std::forward<F>(f)();
 }
 template < 
 class F,
 class U = dlib::remove_cvref_t<dlib::invoke_result_t<F>>,
 std::enable_if_t<std::is_same<U, dlib::optional<T>>::value, bool> = true
 >
 constexpr optional or_else( F&& f ) &&
 {
 return *this ? std::move(*this) : std::forward<F>(f)();
 }
 };
// ---------------------------------------------------------------------------------------------------
 template <class T, class U>
 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() == std::declval<T>()))
 { 
 return bool(lhs) == bool(rhs) && (!bool(lhs) || *lhs == *rhs);
 }
 template <class T, class U> 
 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() != std::declval<T>()))
 { 
 return !(lhs == rhs); 
 }
 
 template <class T, class U> 
 constexpr bool operator<(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() < std::declval<T>()))
 {
 return bool(rhs) && (!bool(lhs) || *lhs < *rhs);
 }
 template <class T, class U>
 constexpr bool operator>=(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() >= std::declval<T>()))
 {
 return !(lhs < rhs);
 }
 
 template <class T, class U>
 constexpr bool operator>(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() > std::declval<T>()))
 {
 return bool(lhs) && (!bool(rhs) || *lhs > *rhs);
 }
 template <class T, class U>
 constexpr bool operator<=(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() <= std::declval<T>()))
 {
 return !(lhs > rhs);
 }
// ---------------------------------------------------------------------------------------------------
 template <class T>
 constexpr bool operator==(const optional<T> &lhs, nullopt_t) noexcept
 {
 return !bool(lhs);
 }
 template <class T>
 constexpr bool operator==(nullopt_t, const optional<T> &rhs) noexcept 
 {
 return !bool(rhs);
 }
 
 template <class T>
 constexpr bool operator!=(const optional<T> &lhs, nullopt_t) noexcept 
 {
 return bool(lhs);
 }
 template <class T>
 constexpr bool operator!=(nullopt_t, const optional<T> &rhs) noexcept 
 {
 return bool(rhs);
 }
 
 template <class T>
 constexpr bool operator<(const optional<T> &, nullopt_t) noexcept 
 {
 return false;
 }
 
 template <class T>
 constexpr bool operator<(nullopt_t, const optional<T> &rhs) noexcept 
 {
 return bool(rhs);
 }
 template <class T>
 constexpr bool operator<=(const optional<T> &lhs, nullopt_t) noexcept
 {
 return !bool(lhs);
 }
 template <class T>
 constexpr bool operator<=(nullopt_t, const optional<T> &) noexcept 
 {
 return true;
 }
 template <class T>
 constexpr bool operator>(const optional<T> &lhs, nullopt_t) noexcept
 {
 return bool(lhs);
 }
 template <class T>
 constexpr bool operator>(nullopt_t, const optional<T> &) noexcept 
 {
 return false;
 }
 template <class T>
 constexpr bool operator>=(const optional<T> &, nullopt_t) noexcept 
 {
 return true;
 }
 template <class T>
 constexpr bool operator>=(nullopt_t, const optional<T> &rhs) noexcept 
 {
 return !rhs.has_value();
 }
// ---------------------------------------------------------------------------------------------------
 template <class T, class U>
 constexpr bool operator==(const optional<T> &lhs, const U &rhs) 
 {
 return bool(lhs) ? *lhs == rhs : false;
 }
 template <class T, class U>
 constexpr bool operator==(const U &lhs, const optional<T> &rhs) 
 {
 return bool(rhs) ? lhs == *rhs : false;
 }
 template <class T, class U>
 constexpr bool operator!=(const optional<T> &lhs, const U &rhs) 
 {
 return bool(lhs) ? *lhs != rhs : true;
 }
 template <class T, class U>
 constexpr bool operator!=(const U &lhs, const optional<T> &rhs) 
 {
 return bool(rhs) ? lhs != *rhs : true;
 }
 template <class T, class U>
 constexpr bool operator<(const optional<T> &lhs, const U &rhs) 
 {
 return bool(lhs) ? *lhs < rhs : true;
 }
 template <class T, class U>
 constexpr bool operator<(const U &lhs, const optional<T> &rhs) 
 {
 return bool(rhs) ? lhs < *rhs : false;
 }
 template <class T, class U>
 constexpr bool operator<=(const optional<T> &lhs, const U &rhs)
 {
 return bool(lhs) ? *lhs <= rhs : true;
 }
 template <class T, class U>
 constexpr bool operator<=(const U &lhs, const optional<T> &rhs)
 {
 return bool(rhs) ? lhs <= *rhs : false;
 }
 template <class T, class U>
 constexpr bool operator>(const optional<T> &lhs, const U &rhs) 
 {
 return bool(lhs) ? *lhs > rhs : false;
 }
 template <class T, class U>
 constexpr bool operator>(const U &lhs, const optional<T> &rhs)
 {
 return bool(rhs) ? lhs > *rhs : true;
 }
 template <class T, class U>
 constexpr bool operator>=(const optional<T> &lhs, const U &rhs) 
 {
 return bool(lhs) ? *lhs >= rhs : false;
 }
 template <class T, class U>
 constexpr bool operator>=(const U &lhs, const optional<T> &rhs)
 {
 return bool(rhs) ? lhs >= *rhs : true;
 }
// ---------------------------------------------------------------------------------------------------
 template <
 class T,
 std::enable_if_t<
 std::is_move_constructible<T>::value &&
 dlib::is_swappable<T>::value,
 bool> = true
 >
 void swap(dlib::optional<T>& lhs, dlib::optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) 
 {
 return lhs.swap(rhs);
 }
// ---------------------------------------------------------------------------------------------------
 template< class T >
 constexpr dlib::optional<std::decay_t<T>> make_optional( T&& value )
 {
 return dlib::optional<std::decay_t<T>>(std::forward<T>(value));
 }
 template< class T, class... Args >
 constexpr dlib::optional<T> make_optional( Args&&... args )
 {
 return dlib::optional<T>(dlib::in_place, std::forward<Args>(args)...);
 }
 template< class T, class U, class... Args >
 constexpr dlib::optional<T> make_optional( std::initializer_list<U> il, Args&&... args )
 {
 return dlib::optional<T>(dlib::in_place, il, std::forward<Args>(args)...);
 }
// ---------------------------------------------------------------------------------------------------
}
#endif

AltStyle によって変換されたページ (->オリジナル) /