/// // optional - An implementation of std::optional with extensions // Written in 2017 by Simon Brand (@TartanLlama) // // 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 // . /// #include #include #include #include #include #if __cplusplus == 201103L || _MSC_VER == 1900 #define TL_OPTIONAL_11_CONSTEXPR #else #define TL_OPTIONAL_11_CONSTEXPR constexpr #endif #if _MSC_VER == 1900 #define TL_OPTIONAL_MSVC_2015_CONSTEXPR #else #define TL_OPTIONAL_MSVC_2015_CONSTEXPR constexpr #endif namespace tl { template class optional; class monostate {}; namespace detail { template using remove_cv_t = typename std::remove_cv::type; template using remove_const_t = typename std::remove_const::type; template using remove_volatile_t = typename std::remove_volatile::type; template using add_cv_t = typename std::add_cv::type; template using add_const_t = typename std::add_const::type; template using add_volatile_t = typename std::add_volatile::type; template using remove_reference_t = typename std::remove_reference::type; template using add_lvalue_reference_t = typename std::add_lvalue_reference::type; template using add_rvalue_reference_t = typename std::add_rvalue_reference::type; template using remove_pointer_t = typename std::remove_pointer::type; template using add_pointer_t = typename std::add_pointer::type; template using make_signed_t = typename std::make_signed::type; template using make_unsigned_t = typename std::make_unsigned::type; template using remove_extent_t = typename std::remove_extent::type; template using remove_all_extents_t = typename std::remove_all_extents::type; template using aligned_storage_t = typename std::aligned_storage::type; template using aligned_union_t = typename std::aligned_union::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; template using common_type_t = typename std::common_type::type; template using underlying_type_t = typename std::underlying_type::type; template using result_of_t = typename std::result_of::type; template struct conjunction : std::true_type {}; template struct conjunction : B {}; template struct conjunction : std::conditional, B>::type {}; template struct voider { using type = void; }; template using void_t = typename voider::type; template struct is_optional_impl : std::false_type {}; template struct is_optional_impl> : std::true_type {}; template using is_optional = is_optional_impl>; // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround template < typename Fn, typename... Args, typename = enable_if_t>{}>, 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 < typename Fn, typename... Args, typename = enable_if_t>{}>> 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)...); } template struct invoke_result_impl; template struct invoke_result_impl< F, decltype(invoke(std::declval(), std::declval()...), void()), Us...> { using type = decltype(invoke(std::declval(), std::declval()...)); }; template using invoke_result = invoke_result_impl; template using invoke_result_t = typename invoke_result::type; template using fixup_void = conditional_t::value, monostate, U>; template struct get_invoke_optional_ret { using type = invoke_result_t< conditional_t::value, typename remove_reference_t::value_type &, typename remove_reference_t::value_type &&>, U...>; }; template using get_invoke_ret = typename conditional_t::value, get_invoke_optional_ret, invoke_result>::type; template using get_map_return = optional>>; template using returns_void = std::is_void>; template using disable_if_optional = enable_if_t::value>; template using enable_if_optional = enable_if_t::value>; template using enable_if_ret_void = enable_if_t::value>; template using disable_if_ret_void = enable_if_t::value>; } // namespace detail struct in_place_t { explicit in_place_t() = default; }; static constexpr in_place_t in_place{}; // [optional.optional], class template optional template class optional; namespace detail { 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< std::is_constructible::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< std::is_constructible::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>; #ifdef _MSC_VER // TODO make a version which works with MSVC 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 } // namespace detail // [optional.nullopt], no-value state indicator 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{}}; // [optional.bad.access], class bad_optional_access class bad_optional_access : public std::exception { public: bad_optional_access() = default; const char *what() const noexcept { return "Optional has no value"; } }; // [optional.relops], relational operators 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); } // [optional.nullops], comparison with nullopt 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(); } // [optional.comp_with_t], comparison with T 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; } // [optional.specalg], specialized algorithms template ::value> * = nullptr, detail::enable_if_t::value> * = nullptr> void swap(optional &lhs, optional &rhs) noexcept(noexcept(lhs.swap(rhs))) { return lhs.swap(rhs); } template inline constexpr optional> make_optional(T &&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)...); } } // namespace tl // [optional.hash], hash support namespace std { // TODO SFINAE template struct hash> { ::std::size_t operator()(const tl::optional &o) const { if (!o.has_value()) return 0; return hash>()(*o); } }; } // namespace std namespace tl { namespace detail { template ::value> struct optional_storage_base { constexpr optional_storage_base() noexcept : m_dummy(), m_has_value(false) {} template constexpr optional_storage_base(in_place_t, U &&... u) noexcept : 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; }; template struct optional_storage_base { constexpr optional_storage_base() noexcept : m_dummy(), m_has_value(false) {} template constexpr optional_storage_base(in_place_t, U &&... u) noexcept : m_value(std::forward(u)...), m_has_value(true) {} ~optional_storage_base() = default; struct dummy {}; union { dummy m_dummy; T m_value; }; bool m_has_value = false; }; } // namespace detail template class optional : private detail::optional_storage_base { using base = detail::optional_storage_base; public: using value_type = T; // [optional.ctor], constructors constexpr optional() noexcept = default; constexpr optional(nullopt_t) noexcept {}; TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) { if (rhs.has_value()) { this->m_has_value = true; new (std::addressof(this->m_value)) T(*rhs); } } // TODO conditionally disable TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) noexcept( std::is_nothrow_move_constructible::value) { if (rhs.has_value()) { this->m_has_value = true; new (std::addressof(this->m_value)) T(std::move(*rhs)); } } 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 &, Args &&...>::value, in_place_t>, std::initializer_list il, Args &&... args) { this->m_has_value = true; new (std::addressof(this->m_value)) T(il, std::forward(args)...); } template < class U = T, detail::enable_if_t::value> * = nullptr, detail::enable_forward_value * = nullptr> constexpr optional(U &&u) : base(in_place, std::forward(u)) {} template < class U = T, detail::enable_if_t::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) { this->m_has_value = true; new (std::addressof(this->m_value)) T(*rhs); } template * = nullptr, detail::enable_if_t::value> * = nullptr> optional(const optional &rhs) { this->m_has_value = true; new (std::addressof(this->m_value)) T(*rhs); } template < class U, detail::enable_from_other * = nullptr, detail::enable_if_t::value> * = nullptr> optional(optional &&rhs) { this->m_has_value = true; new (std::addressof(this->m_value)) T(std::move(*rhs)); } template < class U, detail::enable_from_other * = nullptr, detail::enable_if_t::value> * = nullptr> explicit optional(optional &&rhs) { this->m_has_value = true; new (std::addressof(this->m_value)) T(std::move(*rhs)); } // [optional.dtor], destructor ~optional() = default; // [optional.assign], assignment optional &operator=(nullopt_t) noexcept { if (has_value()) { this->m_value.~T(); this->m_has_value = false; } } // TODO conditionally delete, check exception guarantee optional &operator=(const optional &rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = rhs.m_value; } else { this->m_value.~T(); this->m_has_value = false; } } if (rhs.has_value()) { new (std::addressof(this->m_value)) T(rhs.m_value); this->m_has_value = true; } } // TODO conditionally delete, check exception guarantee optional &operator=(optional &&rhs) noexcept( std::is_nothrow_move_assignable::value &&std::is_nothrow_move_constructible::value) { if (has_value()) { if (rhs.has_value()) { this->m_value = std::move(rhs.m_value); } else { this->m_value.~T(); this->m_has_value = false; } } if (rhs.has_value()) { new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); this->m_has_value = true; } } // TODO conditionally delete, check exception guarantee template * = nullptr> optional &operator=(U &&u) { if (has_value()) { this->m_value = std::forward(u); } else { new (std::addressof(this->m_value)) T(std::forward(u)); this->m_has_value = true; } } // TODO check exception guarantee template * = nullptr> optional &operator=(const optional &rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = rhs.m_value; } else { this->m_value.~T(); this->m_has_value = false; } } if (rhs.has_value()) { new (std::addressof(this->m_value)) T(rhs.m_value); this->m_has_value = true; } } // TODO check exception guarantee template * = nullptr> optional &operator=(optional &&rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = std::move(rhs.m_value); } else { this->m_value.~T(); this->m_has_value = false; } } if (rhs.has_value()) { new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); this->m_has_value = true; } } template T &emplace(Args &&... args) { static_assert(std::is_constructible::value, "T must be constructible with Args"); *this = nullopt; new (std::addressof(this->m_value)) T(std::forward(args)...); } template detail::enable_if_t< std::is_constructible &, Args &&...>::value, T &> emplace(std::initializer_list il, Args &&... args) { *this = nullopt; new (std::addressof(this->m_value)) T(il, std::forward(args)...); } // [optional.swap], swap void swap(optional &rhs) noexcept(std::is_nothrow_move_constructible::value &&detail::is_nothrow_swappable::value) { if (has_value()) { if (rhs.has_value()) { using std::swap; swap(**this, *rhs); } else { new (&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(); } } // [optional.observe], observers constexpr const T *operator->() const { return std::addressof(this->m_value); } TL_OPTIONAL_11_CONSTEXPR T *operator->() { return std::addressof(this->m_value); } constexpr const T &operator*() const & { return this->m_value; } TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; } TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { return std::move(this->m_value); } constexpr const T &&operator*() const && { return std::move(this->m_value); } constexpr explicit operator bool() const noexcept { return this->m_has_value; } constexpr bool has_value() const noexcept { return this->m_has_value; } 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 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(); } constexpr const T &&value() const && { if (has_value()) return std::move(this->m_value); throw bad_optional_access(); } 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 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() ? **this : static_cast(std::forward(u)); } // [optional.mod], modifiers void reset() noexcept { if (has_value()) { this->m_value.~T(); this->m_has_value = false; } } 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); } 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); } template * = nullptr, detail::disable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) & noexcept(noexcept(detail::invoke(std::forward(f), std::declval()))) { using result = detail::get_map_return; return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template * = nullptr, detail::enable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) & { if (!has_value()) return nullopt; detail::invoke(std::forward(f), **this); return monostate{}; } template * = nullptr, detail::disable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) & { using result = detail::get_map_return; return (f.has_value() && has_value()) ? detail::invoke(*std::forward(f), **this) : result(nullopt); } template * = nullptr, detail::enable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) & { if (!f.has_value() || !has_value()) return nullopt; detail::invoke(*std::forward(f), **this); return monostate{}; } template * = nullptr, detail::disable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) && { using result = detail::get_map_return; return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } template * = nullptr, detail::enable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) && { if (!has_value()) return nullopt; detail::invoke(std::forward(f), std::move(**this)); return monostate{}; } template * = nullptr, detail::disable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) && { using result = detail::get_map_return; return (f.has_value() && has_value()) ? detail::invoke(*std::forward(f), std::move(**this)) : result(nullopt); } template * = nullptr, detail::enable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) && { if (!f.has_value() || !has_value()) return nullopt; detail::invoke(*std::forward(f), std::move(**this)); return monostate{}; } template * = nullptr, detail::disable_if_ret_void * = nullptr> constexpr detail::get_map_return map(F &&f) const & { using result = detail::get_map_return; return this->has_value() ? result(detail::invoke(std::forward(f), **this)) : result(nullopt); } template * = nullptr, detail::enable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) const & { if (!has_value()) return nullopt; detail::invoke(std::forward(f), **this); return monostate{}; } template * = nullptr, detail::disable_if_ret_void * = nullptr> constexpr detail::get_map_return map(F &&f) const & { using result = detail::get_map_return; return (f.has_value() && has_value()) ? detail::invoke(*std::forward(f), **this) : result(nullopt); } template * = nullptr, detail::enable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) const & { if (!f.has_value() || !has_value()) return nullopt; detail::invoke(*std::forward(f), **this); return monostate{}; } template * = nullptr, detail::disable_if_ret_void * = nullptr> constexpr detail::get_map_return map(F &&f) const && { using result = detail::get_map_return; return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } template * = nullptr, detail::enable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) const && { if (!has_value()) return nullopt; detail::invoke(std::forward(f), std::move(**this)); return monostate{}; } template * = nullptr, detail::disable_if_ret_void * = nullptr> constexpr detail::get_map_return map(F &&f) const && { using result = detail::get_map_return; return (f.has_value() && has_value()) ? detail::invoke(*std::forward(f), std::move(**this)) : result(nullopt); } template * = nullptr, detail::enable_if_ret_void * = nullptr> detail::get_map_return map(F &&f) const && { if (!f.has_value() || !has_value()) return nullopt; detail::invoke(*std::forward(f), std::move(**this)); return monostate{}; } template * = nullptr> optional TL_OPTIONAL_MSVC_2015_CONSTEXPR or_else(F &&f) & { if (has_value()) return *this; std::forward(f)(); return nullopt; } template * = nullptr> optional TL_OPTIONAL_MSVC_2015_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_MSVC_2015_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_MSVC_2015_CONSTEXPR or_else(F &&f) const & { return has_value() ? *this : std::forward(f)(); } 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)(); } 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); } template U map_or(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } template U map_or_else(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } template U map_or_else(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } template U map_or_else(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } template U map_or_else(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } }; // template optional(T)->optional; } // namespace tl