.. _program_listing_file__tmp_ws_src_proxsuite_include_proxsuite_helpers_tl-optional.hpp: Program Listing for File tl-optional.hpp ======================================== |exhale_lsh| :ref:`Return to documentation for file ` (``/tmp/ws/src/proxsuite/include/proxsuite/helpers/tl-optional.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // optional - An implementation of std::optional with extensions // Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) // // Documentation available at https://tl.tartanllama.xyz/ // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this software to the // public domain worldwide. This software is distributed without any warranty. // // You should have received a copy of the CC0 Public Domain Dedication // along with this software. If not, see // . #ifndef TL_OPTIONAL_HPP #define TL_OPTIONAL_HPP #define TL_OPTIONAL_VERSION_MAJOR 1 #define TL_OPTIONAL_VERSION_MINOR 1 #define TL_OPTIONAL_VERSION_PATCH 0 #include #include #include #include #include #if (defined(_MSC_VER) && _MSC_VER == 1900) #define TL_OPTIONAL_MSVC2015 #endif #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ !defined(__clang__)) #define TL_OPTIONAL_GCC49 #endif #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ !defined(__clang__)) #define TL_OPTIONAL_GCC54 #endif #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ !defined(__clang__)) #define TL_OPTIONAL_GCC55 #endif #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ !defined(__clang__)) // GCC < 5 doesn't support overloading on const&& for member functions #define TL_OPTIONAL_NO_CONSTRR // GCC < 5 doesn't support some standard C++11 type traits #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ std::has_trivial_copy_constructor::value #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::has_trivial_copy_assign::value // This one will be different for GCC 5.7 if it's ever supported #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \ std::is_trivially_destructible::value // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks // std::vector for non-copyable types #elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX namespace tl { namespace detail { template struct is_trivially_copy_constructible : std::is_trivially_copy_constructible {}; #ifdef _GLIBCXX_VECTOR template struct is_trivially_copy_constructible> : std::is_trivially_copy_constructible {}; #endif } } #endif #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ tl::detail::is_trivially_copy_constructible::value #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::is_trivially_copy_assignable::value #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \ std::is_trivially_destructible::value #else #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ std::is_trivially_copy_constructible::value #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::is_trivially_copy_assignable::value #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \ std::is_trivially_destructible::value #endif #if __cplusplus > 201103L #define TL_OPTIONAL_CXX14 #endif // constexpr implies const in C++11, not C++14 #if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \ defined(TL_OPTIONAL_GCC49)) #define TL_OPTIONAL_11_CONSTEXPR #else #define TL_OPTIONAL_11_CONSTEXPR constexpr #endif namespace tl { #ifndef TL_MONOSTATE_INPLACE_MUTEX #define TL_MONOSTATE_INPLACE_MUTEX class monostate {}; struct in_place_t { explicit in_place_t() = default; }; static constexpr in_place_t in_place{}; #endif template class optional; namespace detail { #ifndef TL_TRAITS_MUTEX #define TL_TRAITS_MUTEX // C++14-style aliases for brevity template using remove_const_t = typename std::remove_const::type; template using remove_reference_t = typename std::remove_reference::type; template using decay_t = typename std::decay::type; template using enable_if_t = typename std::enable_if::type; template using conditional_t = typename std::conditional::type; // std::conjunction from C++17 template struct conjunction : std::true_type {}; template struct conjunction : B {}; template struct conjunction : std::conditional, B>::type {}; #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L #define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND #endif // In C++11 mode, there's an issue in libc++'s std::mem_fn // which results in a hard-error when using it in a noexcept expression // in some cases. This is a check to workaround the common failing case. #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND template struct is_pointer_to_non_const_member_func : std::false_type {}; template struct is_pointer_to_non_const_member_func : std::true_type {}; template struct is_pointer_to_non_const_member_func : std::true_type {}; template struct is_pointer_to_non_const_member_func : std::true_type {}; template struct is_pointer_to_non_const_member_func : std::true_type {}; template struct is_pointer_to_non_const_member_func : std::true_type {}; template struct is_pointer_to_non_const_member_func : std::true_type {}; template struct is_const_or_const_ref : std::false_type {}; template struct is_const_or_const_ref : std::true_type {}; template struct is_const_or_const_ref : std::true_type {}; #endif // std::invoke from C++17 // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround template< typename Fn, typename... Args, #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND typename = enable_if_t::value && is_const_or_const_ref::value)>, #endif typename = enable_if_t>::value>, int = 0> constexpr auto invoke(Fn&& f, Args&&... args) noexcept( noexcept(std::mem_fn(f)(std::forward(args)...))) -> decltype(std::mem_fn(f)(std::forward(args)...)) { return std::mem_fn(f)(std::forward(args)...); } template>::value>> constexpr auto invoke(Fn&& f, Args&&... args) noexcept( noexcept(std::forward(f)(std::forward(args)...))) -> decltype(std::forward(f)(std::forward(args)...)) { return std::forward(f)(std::forward(args)...); } // std::invoke_result from C++17 template struct invoke_result_impl; template struct invoke_result_impl< F, decltype(detail::invoke(std::declval(), std::declval()...), void()), Us...> { using type = decltype(detail::invoke(std::declval(), std::declval()...)); }; template using invoke_result = invoke_result_impl; template using invoke_result_t = typename invoke_result::type; #if defined(_MSC_VER) && _MSC_VER <= 1900 // TODO make a version which works with MSVC 2015 template struct is_swappable : std::true_type {}; template struct is_nothrow_swappable : std::true_type {}; #else // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept namespace swap_adl_tests { // if swap ADL finds this then it would call std::swap otherwise (same // signature) struct tag {}; template tag swap(T&, T&); template tag swap(T (&a)[N], T (&b)[N]); // helper functions to test if an unqualified swap is possible, and if it // becomes std::swap template std::false_type can_swap(...) noexcept(false); template(), std::declval()))> std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), std::declval()))); template std::false_type uses_std(...); template std::is_same(), std::declval())), tag> uses_std(int); template struct is_std_swap_noexcept : std::integral_constant::value && std::is_nothrow_move_assignable::value> {}; template struct is_std_swap_noexcept : is_std_swap_noexcept {}; template struct is_adl_swap_noexcept : std::integral_constant(0))> {}; } // namespace swap_adl_tests template struct is_swappable : std::integral_constant< bool, decltype(detail::swap_adl_tests::can_swap(0))::value && (!decltype(detail::swap_adl_tests::uses_std(0))::value || (std::is_move_assignable::value && std::is_move_constructible::value))> {}; template struct is_swappable : std::integral_constant< bool, decltype(detail::swap_adl_tests::can_swap(0))::value && (!decltype(detail::swap_adl_tests::uses_std(0))::value || is_swappable::value)> {}; template struct is_nothrow_swappable : std::integral_constant< bool, is_swappable::value && ((decltype(detail::swap_adl_tests::uses_std(0))::value && detail::swap_adl_tests::is_std_swap_noexcept::value) || (!decltype(detail::swap_adl_tests::uses_std(0))::value && detail::swap_adl_tests::is_adl_swap_noexcept::value))> {}; #endif #endif // std::void_t from C++17 template struct voider { using type = void; }; template using void_t = typename voider::type; // Trait for checking if a type is a tl::optional template struct is_optional_impl : std::false_type {}; template struct is_optional_impl> : std::true_type {}; template using is_optional = is_optional_impl>; // Change void to tl::monostate template using fixup_void = conditional_t::value, monostate, U>; template> using get_map_return = optional>>; // Check if invoking F for some Us returns void template struct returns_void_impl; template struct returns_void_impl>, U...> : std::is_void> {}; template using returns_void = returns_void_impl; template using enable_if_ret_void = enable_if_t::value>; template using disable_if_ret_void = enable_if_t::value>; template using enable_forward_value = detail::enable_if_t::value && !std::is_same, in_place_t>::value && !std::is_same, detail::decay_t>::value>; template using enable_from_other = detail::enable_if_t::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value>; template using enable_assign_forward = detail::enable_if_t< !std::is_same, detail::decay_t>::value && !detail::conjunction, std::is_same>>::value && std::is_constructible::value && std::is_assignable::value>; template using enable_assign_from_other = detail::enable_if_t::value && std::is_assignable::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_assignable&>::value && !std::is_assignable&&>::value && !std::is_assignable&>::value && !std::is_assignable&&>::value>; // The storage base manages the actual storage, and correctly propagates // trivial destruction from T. This case is for when T is not trivially // destructible. template::value> struct optional_storage_base { TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy() , m_has_value(false) { } template TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward(u)...) , m_has_value(true) { } ~optional_storage_base() { if (m_has_value) { m_value.~T(); m_has_value = false; } } struct dummy {}; union { dummy m_dummy; T m_value; }; bool m_has_value; }; // This case is for when T is trivially destructible. template struct optional_storage_base { TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy() , m_has_value(false) { } template TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward(u)...) , m_has_value(true) { } // No destructor, so this class is trivially destructible struct dummy {}; union { dummy m_dummy; T m_value; }; bool m_has_value = false; }; // This base class provides some handy member functions which can be used in // further derived classes template struct optional_operations_base : optional_storage_base { using optional_storage_base::optional_storage_base; void hard_reset() noexcept { get().~T(); this->m_has_value = false; } template void construct(Args&&... args) { new (std::addressof(this->m_value)) T(std::forward(args)...); this->m_has_value = true; } template void assign(Opt&& rhs) { if (this->has_value()) { if (rhs.has_value()) { this->m_value = std::forward(rhs).get(); } else { this->m_value.~T(); this->m_has_value = false; } } else if (rhs.has_value()) { construct(std::forward(rhs).get()); } } bool has_value() const { return this->m_has_value; } TL_OPTIONAL_11_CONSTEXPR T& get() & { return this->m_value; } TL_OPTIONAL_11_CONSTEXPR const T& get() const& { return this->m_value; } TL_OPTIONAL_11_CONSTEXPR T&& get() && { return std::move(this->m_value); } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr const T&& get() const&& { return std::move(this->m_value); } #endif }; // This class manages conditionally having a trivial copy constructor // This specialization is for when T is trivially copy constructible template struct optional_copy_base : optional_operations_base { using optional_operations_base::optional_operations_base; }; // This specialization is for when T is not trivially copy constructible template struct optional_copy_base : optional_operations_base { using optional_operations_base::optional_operations_base; optional_copy_base() = default; optional_copy_base(const optional_copy_base& rhs) : optional_operations_base() { if (rhs.has_value()) { this->construct(rhs.get()); } else { this->m_has_value = false; } } optional_copy_base(optional_copy_base&& rhs) = default; optional_copy_base& operator=(const optional_copy_base& rhs) = default; optional_copy_base& operator=(optional_copy_base&& rhs) = default; }; // This class manages conditionally having a trivial move constructor // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it // doesn't implement an analogue to std::is_trivially_move_constructible. We // have to make do with a non-trivial move constructor even if T is trivially // move constructible #ifndef TL_OPTIONAL_GCC49 template::value> struct optional_move_base : optional_copy_base { using optional_copy_base::optional_copy_base; }; #else template struct optional_move_base; #endif template struct optional_move_base : optional_copy_base { using optional_copy_base::optional_copy_base; optional_move_base() = default; optional_move_base(const optional_move_base& rhs) = default; optional_move_base(optional_move_base&& rhs) noexcept( std::is_nothrow_move_constructible::value) { if (rhs.has_value()) { this->construct(std::move(rhs.get())); } else { this->m_has_value = false; } } optional_move_base& operator=(const optional_move_base& rhs) = default; optional_move_base& operator=(optional_move_base&& rhs) = default; }; // This class manages conditionally having a trivial copy assignment operator template struct optional_copy_assign_base : optional_move_base { using optional_move_base::optional_move_base; }; template struct optional_copy_assign_base : optional_move_base { using optional_move_base::optional_move_base; optional_copy_assign_base() = default; optional_copy_assign_base(const optional_copy_assign_base& rhs) = default; optional_copy_assign_base(optional_copy_assign_base&& rhs) = default; optional_copy_assign_base& operator=(const optional_copy_assign_base& rhs) { this->assign(rhs); return *this; } optional_copy_assign_base& operator=(optional_copy_assign_base&& rhs) = default; }; // This class manages conditionally having a trivial move assignment operator // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it // doesn't implement an analogue to std::is_trivially_move_assignable. We have // to make do with a non-trivial move assignment operator even if T is trivially // move assignable #ifndef TL_OPTIONAL_GCC49 template::value&& std::is_trivially_move_constructible::value&& std::is_trivially_move_assignable::value> struct optional_move_assign_base : optional_copy_assign_base { using optional_copy_assign_base::optional_copy_assign_base; }; #else template struct optional_move_assign_base; #endif template struct optional_move_assign_base : optional_copy_assign_base { using optional_copy_assign_base::optional_copy_assign_base; optional_move_assign_base() = default; optional_move_assign_base(const optional_move_assign_base& rhs) = default; optional_move_assign_base(optional_move_assign_base&& rhs) = default; optional_move_assign_base& operator=(const optional_move_assign_base& rhs) = default; optional_move_assign_base& operator=(optional_move_assign_base&& rhs) noexcept( std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value) { this->assign(std::move(rhs)); return *this; } }; // optional_delete_ctor_base will conditionally delete copy and move // constructors depending on whether T is copy/move constructible template::value, bool EnableMove = std::is_move_constructible::value> struct optional_delete_ctor_base { optional_delete_ctor_base() = default; optional_delete_ctor_base(const optional_delete_ctor_base&) = default; optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default; optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; }; template struct optional_delete_ctor_base { optional_delete_ctor_base() = default; optional_delete_ctor_base(const optional_delete_ctor_base&) = default; optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete; optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; }; template struct optional_delete_ctor_base { optional_delete_ctor_base() = default; optional_delete_ctor_base(const optional_delete_ctor_base&) = delete; optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default; optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; }; template struct optional_delete_ctor_base { optional_delete_ctor_base() = default; optional_delete_ctor_base(const optional_delete_ctor_base&) = delete; optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete; optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; }; // optional_delete_assign_base will conditionally delete copy and move // constructors depending on whether T is copy/move constructible + assignable template::value && std::is_copy_assignable::value), bool EnableMove = (std::is_move_constructible::value && std::is_move_assignable::value)> struct optional_delete_assign_base { optional_delete_assign_base() = default; optional_delete_assign_base(const optional_delete_assign_base&) = default; optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default; optional_delete_assign_base& operator=( optional_delete_assign_base&&) noexcept = default; }; template struct optional_delete_assign_base { optional_delete_assign_base() = default; optional_delete_assign_base(const optional_delete_assign_base&) = default; optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default; optional_delete_assign_base& operator=( optional_delete_assign_base&&) noexcept = delete; }; template struct optional_delete_assign_base { optional_delete_assign_base() = default; optional_delete_assign_base(const optional_delete_assign_base&) = default; optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete; optional_delete_assign_base& operator=( optional_delete_assign_base&&) noexcept = default; }; template struct optional_delete_assign_base { optional_delete_assign_base() = default; optional_delete_assign_base(const optional_delete_assign_base&) = default; optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete; optional_delete_assign_base& operator=( optional_delete_assign_base&&) noexcept = delete; }; } // namespace detail struct nullopt_t { struct do_not_use {}; constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {} }; static constexpr nullopt_t nullopt{ nullopt_t::do_not_use{}, nullopt_t::do_not_use{} }; class bad_optional_access : public std::exception { public: bad_optional_access() = default; const char* what() const noexcept { return "Optional has no value"; } }; template class optional : private detail::optional_move_assign_base , private detail::optional_delete_ctor_base , private detail::optional_delete_assign_base { using base = detail::optional_move_assign_base; static_assert(!std::is_same::value, "instantiation of optional with in_place_t is ill-formed"); static_assert(!std::is_same, nullopt_t>::value, "instantiation of optional with nullopt_t is ill-formed"); public: // The different versions for C++14 and 11 are needed because deduced return // types are not SFINAE-safe. This provides better support for things like // generic lambdas. C.f. // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) template TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } template constexpr auto and_then(F&& f) const& { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr auto and_then(F&& f) const&& { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } #endif #else template TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F&& f) & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F&& f) && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } template constexpr detail::invoke_result_t and_then(F&& f) const& { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr detail::invoke_result_t and_then(F&& f) const&& { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) template TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & { return optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && { return optional_map_impl(std::move(*this), std::forward(f)); } template constexpr auto map(F&& f) const& { return optional_map_impl(*this, std::forward(f)); } template constexpr auto map(F&& f) const&& { return optional_map_impl(std::move(*this), std::forward(f)); } #else template TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), std::declval())) map(F&& f) & { return optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl( std::declval(), std::declval())) map(F&& f) && { return optional_map_impl(std::move(*this), std::forward(f)); } template constexpr decltype(optional_map_impl(std::declval(), std::declval())) map(F&& f) const& { return optional_map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr decltype(optional_map_impl(std::declval(), std::declval())) map(F&& f) const&& { return optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) & { return optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) && { return optional_map_impl(std::move(*this), std::forward(f)); } template constexpr auto transform(F&& f) const& { return optional_map_impl(*this, std::forward(f)); } template constexpr auto transform(F&& f) const&& { return optional_map_impl(std::move(*this), std::forward(f)); } #else template TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), std::declval())) transform(F&& f) & { return optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl( std::declval(), std::declval())) transform(F&& f) && { return optional_map_impl(std::move(*this), std::forward(f)); } template constexpr decltype(optional_map_impl(std::declval(), std::declval())) transform(F&& f) const& { return optional_map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr decltype(optional_map_impl(std::declval(), std::declval())) transform(F&& f) const&& { return optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif template* = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { if (has_value()) return *this; std::forward(f)(); return nullopt; } template* = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { return has_value() ? *this : std::forward(f)(); } template* = nullptr> optional or_else(F&& f) && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } template* = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && { return has_value() ? std::move(*this) : std::forward(f)(); } template* = nullptr> optional or_else(F&& f) const& { if (has_value()) return *this; std::forward(f)(); return nullopt; } template* = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& { return has_value() ? *this : std::forward(f)(); } #ifndef TL_OPTIONAL_NO_CONSTRR template* = nullptr> optional or_else(F&& f) const&& { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } template* = nullptr> optional or_else(F&& f) const&& { return has_value() ? std::move(*this) : std::forward(f)(); } #endif template U map_or(F&& f, U&& u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } template U map_or(F&& f, U&& u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } template U map_or(F&& f, U&& u) const& { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } #ifndef TL_OPTIONAL_NO_CONSTRR template U map_or(F&& f, U&& u) const&& { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } #endif template detail::invoke_result_t map_or_else(F&& f, U&& u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } template detail::invoke_result_t map_or_else(F&& f, U&& u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } template detail::invoke_result_t map_or_else(F&& f, U&& u) const& { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } #ifndef TL_OPTIONAL_NO_CONSTRR template detail::invoke_result_t map_or_else(F&& f, U&& u) const&& { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } #endif template constexpr optional::type> conjunction(U&& u) const { using result = optional>; return has_value() ? result{ u } : result{ nullopt }; } TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & { return has_value() ? *this : rhs; } constexpr optional disjunction(const optional& rhs) const& { return has_value() ? *this : rhs; } TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && { return has_value() ? std::move(*this) : rhs; } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr optional disjunction(const optional& rhs) const&& { return has_value() ? std::move(*this) : rhs; } #endif TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & { return has_value() ? *this : std::move(rhs); } constexpr optional disjunction(optional&& rhs) const& { return has_value() ? *this : std::move(rhs); } TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && { return has_value() ? std::move(*this) : std::move(rhs); } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr optional disjunction(optional&& rhs) const&& { return has_value() ? std::move(*this) : std::move(rhs); } #endif optional take() { optional ret = std::move(*this); reset(); return ret; } using value_type = T; constexpr optional() noexcept = default; constexpr optional(nullopt_t) noexcept {} TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) = default; TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default; template constexpr explicit optional( detail::enable_if_t::value, in_place_t>, Args&&... args) : base(in_place, std::forward(args)...) { } template TL_OPTIONAL_11_CONSTEXPR explicit optional( detail::enable_if_t< std::is_constructible&, Args&&...>::value, in_place_t>, std::initializer_list il, Args&&... args) { this->construct(il, std::forward(args)...); } template::value>* = nullptr, detail::enable_forward_value* = nullptr> constexpr optional(U&& u) : base(in_place, std::forward(u)) { } template::value>* = nullptr, detail::enable_forward_value* = nullptr> constexpr explicit optional(U&& u) : base(in_place, std::forward(u)) { } template< class U, detail::enable_from_other* = nullptr, detail::enable_if_t::value>* = nullptr> optional(const optional& rhs) { if (rhs.has_value()) { this->construct(*rhs); } } template< class U, detail::enable_from_other* = nullptr, detail::enable_if_t::value>* = nullptr> explicit optional(const optional& rhs) { if (rhs.has_value()) { this->construct(*rhs); } } template* = nullptr, detail::enable_if_t::value>* = nullptr> optional(optional&& rhs) { if (rhs.has_value()) { this->construct(std::move(*rhs)); } } template* = nullptr, detail::enable_if_t::value>* = nullptr> explicit optional(optional&& rhs) { if (rhs.has_value()) { this->construct(std::move(*rhs)); } } ~optional() = default; optional& operator=(nullopt_t) noexcept { if (has_value()) { this->m_value.~T(); this->m_has_value = false; } return *this; } optional& operator=(const optional& rhs) = default; optional& operator=(optional&& rhs) = default; template* = nullptr> optional& operator=(U&& u) { if (has_value()) { this->m_value = std::forward(u); } else { this->construct(std::forward(u)); } return *this; } template* = nullptr> optional& operator=(const optional& rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = *rhs; } else { this->hard_reset(); } } else if (rhs.has_value()) { this->construct(*rhs); } return *this; } // TODO check exception guarantee template* = nullptr> optional& operator=(optional&& rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = std::move(*rhs); } else { this->hard_reset(); } } else if (rhs.has_value()) { this->construct(std::move(*rhs)); } return *this; } template T& emplace(Args&&... args) { static_assert(std::is_constructible::value, "T must be constructible with Args"); *this = nullopt; this->construct(std::forward(args)...); return value(); } template detail::enable_if_t< std::is_constructible&, Args&&...>::value, T&> emplace(std::initializer_list il, Args&&... args) { *this = nullopt; this->construct(il, std::forward(args)...); return value(); } void swap(optional& rhs) noexcept( std::is_nothrow_move_constructible::value&& detail::is_nothrow_swappable::value) { using std::swap; if (has_value()) { if (rhs.has_value()) { swap(**this, *rhs); } else { new (std::addressof(rhs.m_value)) T(std::move(this->m_value)); this->m_value.T::~T(); } } else if (rhs.has_value()) { new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); rhs.m_value.T::~T(); } swap(this->m_has_value, rhs.m_has_value); } constexpr const T* operator->() const { return std::addressof(this->m_value); } TL_OPTIONAL_11_CONSTEXPR T* operator->() { return std::addressof(this->m_value); } TL_OPTIONAL_11_CONSTEXPR T& operator*() & { return this->m_value; } constexpr const T& operator*() const& { return this->m_value; } TL_OPTIONAL_11_CONSTEXPR T&& operator*() && { return std::move(this->m_value); } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr const T&& operator*() const&& { return std::move(this->m_value); } #endif constexpr bool has_value() const noexcept { return this->m_has_value; } constexpr explicit operator bool() const noexcept { return this->m_has_value; } TL_OPTIONAL_11_CONSTEXPR T& value() & { if (has_value()) return this->m_value; throw bad_optional_access(); } TL_OPTIONAL_11_CONSTEXPR const T& value() const& { if (has_value()) return this->m_value; throw bad_optional_access(); } TL_OPTIONAL_11_CONSTEXPR T&& value() && { if (has_value()) return std::move(this->m_value); throw bad_optional_access(); } #ifndef TL_OPTIONAL_NO_CONSTRR TL_OPTIONAL_11_CONSTEXPR const T&& value() const&& { if (has_value()) return std::move(this->m_value); throw bad_optional_access(); } #endif template constexpr T value_or(U&& u) const& { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } template TL_OPTIONAL_11_CONSTEXPR T value_or(U&& u) && { static_assert(std::is_move_constructible::value && std::is_convertible::value, "T must be move constructible and convertible from U"); return has_value() ? std::move(**this) : static_cast(std::forward(u)); } void reset() noexcept { if (has_value()) { this->m_value.~T(); this->m_has_value = false; } } }; // namespace tl template inline constexpr bool operator==(const optional& lhs, const optional& rhs) { return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); } template inline constexpr bool operator!=(const optional& lhs, const optional& rhs) { return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs); } template inline constexpr bool operator<(const optional& lhs, const optional& rhs) { return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); } template inline constexpr bool operator>(const optional& lhs, const optional& rhs) { return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); } template inline constexpr bool operator<=(const optional& lhs, const optional& rhs) { return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); } template inline constexpr bool operator>=(const optional& lhs, const optional& rhs) { return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); } template inline constexpr bool operator==(const optional& lhs, nullopt_t) noexcept { return !lhs.has_value(); } template inline constexpr bool operator==(nullopt_t, const optional& rhs) noexcept { return !rhs.has_value(); } template inline constexpr bool operator!=(const optional& lhs, nullopt_t) noexcept { return lhs.has_value(); } template inline constexpr bool operator!=(nullopt_t, const optional& rhs) noexcept { return rhs.has_value(); } template inline constexpr bool operator<(const optional&, nullopt_t) noexcept { return false; } template inline constexpr bool operator<(nullopt_t, const optional& rhs) noexcept { return rhs.has_value(); } template inline constexpr bool operator<=(const optional& lhs, nullopt_t) noexcept { return !lhs.has_value(); } template inline constexpr bool operator<=(nullopt_t, const optional&) noexcept { return true; } template inline constexpr bool operator>(const optional& lhs, nullopt_t) noexcept { return lhs.has_value(); } template inline constexpr bool operator>(nullopt_t, const optional&) noexcept { return false; } template inline constexpr bool operator>=(const optional&, nullopt_t) noexcept { return true; } template inline constexpr bool operator>=(nullopt_t, const optional& rhs) noexcept { return !rhs.has_value(); } template inline constexpr bool operator==(const optional& lhs, const U& rhs) { return lhs.has_value() ? *lhs == rhs : false; } template inline constexpr bool operator==(const U& lhs, const optional& rhs) { return rhs.has_value() ? lhs == *rhs : false; } template inline constexpr bool operator!=(const optional& lhs, const U& rhs) { return lhs.has_value() ? *lhs != rhs : true; } template inline constexpr bool operator!=(const U& lhs, const optional& rhs) { return rhs.has_value() ? lhs != *rhs : true; } template inline constexpr bool operator<(const optional& lhs, const U& rhs) { return lhs.has_value() ? *lhs < rhs : true; } template inline constexpr bool operator<(const U& lhs, const optional& rhs) { return rhs.has_value() ? lhs < *rhs : false; } template inline constexpr bool operator<=(const optional& lhs, const U& rhs) { return lhs.has_value() ? *lhs <= rhs : true; } template inline constexpr bool operator<=(const U& lhs, const optional& rhs) { return rhs.has_value() ? lhs <= *rhs : false; } template inline constexpr bool operator>(const optional& lhs, const U& rhs) { return lhs.has_value() ? *lhs > rhs : false; } template inline constexpr bool operator>(const U& lhs, const optional& rhs) { return rhs.has_value() ? lhs > *rhs : true; } template inline constexpr bool operator>=(const optional& lhs, const U& rhs) { return lhs.has_value() ? *lhs >= rhs : false; } template inline constexpr bool operator>=(const U& lhs, const optional& rhs) { return rhs.has_value() ? lhs >= *rhs : true; } template::value>* = nullptr, detail::enable_if_t::value>* = nullptr> void swap(optional& lhs, optional& rhs) noexcept(noexcept(lhs.swap(rhs))) { return lhs.swap(rhs); } namespace detail { struct i_am_secret {}; } // namespace detail template< class T = detail::i_am_secret, class U, class Ret = detail::conditional_t::value, detail::decay_t, T>> inline constexpr optional make_optional(U&& v) { return optional(std::forward(v)); } template inline constexpr optional make_optional(Args&&... args) { return optional(in_place, std::forward(args)...); } template inline constexpr optional make_optional(std::initializer_list il, Args&&... args) { return optional(in_place, il, std::forward(args)...); } #if __cplusplus >= 201703L template optional(T) -> optional; #endif namespace detail { #ifdef TL_OPTIONAL_CXX14 template(), *std::declval())), detail::enable_if_t::value>* = nullptr> constexpr auto optional_map_impl(Opt&& opt, F&& f) { return opt.has_value() ? detail::invoke(std::forward(f), *std::forward(opt)) : optional(nullopt); } template(), *std::declval())), detail::enable_if_t::value>* = nullptr> auto optional_map_impl(Opt&& opt, F&& f) { if (opt.has_value()) { detail::invoke(std::forward(f), *std::forward(opt)); return make_optional(monostate{}); } return optional(nullopt); } #else template(), *std::declval())), detail::enable_if_t::value>* = nullptr> constexpr auto optional_map_impl(Opt&& opt, F&& f) -> optional { return opt.has_value() ? detail::invoke(std::forward(f), *std::forward(opt)) : optional(nullopt); } template(), *std::declval())), detail::enable_if_t::value>* = nullptr> auto optional_map_impl(Opt&& opt, F&& f) -> optional { if (opt.has_value()) { detail::invoke(std::forward(f), *std::forward(opt)); return monostate{}; } return nullopt; } #endif } // namespace detail template class optional { public: // The different versions for C++14 and 11 are needed because deduced return // types are not SFINAE-safe. This provides better support for things like // generic lambdas. C.f. // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) template TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template constexpr auto and_then(F&& f) const& { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr auto and_then(F&& f) const&& { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #endif #else template TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F&& f) & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F&& f) && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template constexpr detail::invoke_result_t and_then(F&& f) const& { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr detail::invoke_result_t and_then(F&& f) const&& { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) template TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & { return detail::optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } template constexpr auto map(F&& f) const& { return detail::optional_map_impl(*this, std::forward(f)); } template constexpr auto map(F&& f) const&& { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #else template TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl( std::declval(), std::declval())) map(F&& f) & { return detail::optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl( std::declval(), std::declval())) map(F&& f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } template constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F&& f) const& { return detail::optional_map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F&& f) const&& { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) & { return detail::optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } template constexpr auto transform(F&& f) const& { return detail::optional_map_impl(*this, std::forward(f)); } template constexpr auto transform(F&& f) const&& { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #else template TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl( std::declval(), std::declval())) transform(F&& f) & { return detail::optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl( std::declval(), std::declval())) transform(F&& f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } template constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) transform(F&& f) const& { return detail::optional_map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) transform(F&& f) const&& { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif template* = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { if (has_value()) return *this; std::forward(f)(); return nullopt; } template* = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { return has_value() ? *this : std::forward(f)(); } template* = nullptr> optional or_else(F&& f) && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } template* = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && { return has_value() ? std::move(*this) : std::forward(f)(); } template* = nullptr> optional or_else(F&& f) const& { if (has_value()) return *this; std::forward(f)(); return nullopt; } template* = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& { return has_value() ? *this : std::forward(f)(); } #ifndef TL_OPTIONAL_NO_CONSTRR template* = nullptr> optional or_else(F&& f) const&& { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } template* = nullptr> optional or_else(F&& f) const&& { return has_value() ? std::move(*this) : std::forward(f)(); } #endif template U map_or(F&& f, U&& u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } template U map_or(F&& f, U&& u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } template U map_or(F&& f, U&& u) const& { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } #ifndef TL_OPTIONAL_NO_CONSTRR template U map_or(F&& f, U&& u) const&& { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } #endif template detail::invoke_result_t map_or_else(F&& f, U&& u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } template detail::invoke_result_t map_or_else(F&& f, U&& u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } template detail::invoke_result_t map_or_else(F&& f, U&& u) const& { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } #ifndef TL_OPTIONAL_NO_CONSTRR template detail::invoke_result_t map_or_else(F&& f, U&& u) const&& { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } #endif template constexpr optional::type> conjunction(U&& u) const { using result = optional>; return has_value() ? result{ u } : result{ nullopt }; } TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & { return has_value() ? *this : rhs; } constexpr optional disjunction(const optional& rhs) const& { return has_value() ? *this : rhs; } TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && { return has_value() ? std::move(*this) : rhs; } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr optional disjunction(const optional& rhs) const&& { return has_value() ? std::move(*this) : rhs; } #endif TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & { return has_value() ? *this : std::move(rhs); } constexpr optional disjunction(optional&& rhs) const& { return has_value() ? *this : std::move(rhs); } TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && { return has_value() ? std::move(*this) : std::move(rhs); } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr optional disjunction(optional&& rhs) const&& { return has_value() ? std::move(*this) : std::move(rhs); } #endif optional take() { optional ret = std::move(*this); reset(); return ret; } using value_type = T&; constexpr optional() noexcept : m_value(nullptr) { } constexpr optional(nullopt_t) noexcept : m_value(nullptr) { } TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) noexcept = default; TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default; template>::value>* = nullptr> constexpr optional(U&& u) noexcept : m_value(std::addressof(u)) { static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); } template constexpr explicit optional(const optional& rhs) noexcept : optional(*rhs) { } ~optional() = default; optional& operator=(nullopt_t) noexcept { m_value = nullptr; return *this; } optional& operator=(const optional& rhs) = default; template>::value>* = nullptr> optional& operator=(U&& u) { static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); m_value = std::addressof(u); return *this; } template optional& operator=(const optional& rhs) noexcept { m_value = std::addressof(rhs.value()); return *this; } template>::value>* = nullptr> optional& emplace(U&& u) noexcept { return *this = std::forward(u); } void swap(optional& rhs) noexcept { std::swap(m_value, rhs.m_value); } constexpr const T* operator->() const noexcept { return m_value; } TL_OPTIONAL_11_CONSTEXPR T* operator->() noexcept { return m_value; } TL_OPTIONAL_11_CONSTEXPR T& operator*() noexcept { return *m_value; } constexpr const T& operator*() const noexcept { return *m_value; } constexpr bool has_value() const noexcept { return m_value != nullptr; } constexpr explicit operator bool() const noexcept { return m_value != nullptr; } TL_OPTIONAL_11_CONSTEXPR T& value() { if (has_value()) return *m_value; throw bad_optional_access(); } TL_OPTIONAL_11_CONSTEXPR const T& value() const { if (has_value()) return *m_value; throw bad_optional_access(); } template constexpr T value_or(U&& u) const& noexcept { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } template TL_OPTIONAL_11_CONSTEXPR T value_or(U&& u) && noexcept { static_assert(std::is_move_constructible::value && std::is_convertible::value, "T must be move constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } void reset() noexcept { m_value = nullptr; } private: T* m_value; }; // namespace tl } // namespace tl namespace std { // TODO SFINAE template struct hash> { ::std::size_t operator()(const tl::optional& o) const { if (!o.has_value()) return 0; return std::hash>()(*o); } }; } // namespace std #endif