| // <expected> -*- C++ -*- | |
| // Copyright The GNU Toolchain Authors. | |
| // | |
| // This file is part of the GNU ISO C++ Library. This library is free | |
| // software; you can redistribute it and/or modify it under the | |
| // terms of the GNU General Public License as published by the | |
| // Free Software Foundation; either version 3, or (at your option) | |
| // any later version. | |
| // This library is distributed in the hope that it will be useful, | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| // GNU General Public License for more details. | |
| // Under Section 7 of GPL version 3, you are granted additional | |
| // permissions described in the GCC Runtime Library Exception, version | |
| // 3.1, as published by the Free Software Foundation. | |
| // You should have received a copy of the GNU General Public License and | |
| // a copy of the GCC Runtime Library Exception along with this program; | |
| // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
| // <http://www.gnu.org/licenses/>. | |
| /** @file include/expected | |
| * This is a Standard C++ Library header. | |
| */ | |
| #ifndef _GLIBCXX_EXPECTED | |
| #define _GLIBCXX_EXPECTED | |
| #ifdef _GLIBCXX_SYSHDR | |
| #pragma GCC system_header | |
| #endif | |
| #define __glibcxx_want_expected | |
| #define __glibcxx_want_freestanding_expected | |
| #define __glibcxx_want_constrained_equality | |
| #define __glibcxx_want_constexpr_exceptions | |
| #define __glibcxx_want_hardened_expected | |
| #include <bits/version.h> | |
| #ifdef __cpp_lib_expected // C++ >= 23 && __cpp_concepts >= 202002L | |
| #include <initializer_list> | |
| #include <bits/exception.h> // exception | |
| #include <bits/invoke.h> // __invoke | |
| #include <bits/stl_construct.h> // construct_at | |
| #include <bits/utility.h> // in_place_t | |
| namespace std _GLIBCXX_VISIBILITY(default) | |
| { | |
| _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
| /** | |
| * @defgroup expected_values Expected values | |
| * @addtogroup utilities | |
| * @since C++23 | |
| * @{ | |
| */ | |
| /// Discriminated union that holds an expected value or an error value. | |
| /** | |
| * @since C++23 | |
| */ | |
| template<typename _Tp, typename _Er> | |
| class expected; | |
| /// Wrapper type used to pass an error value to a `std::expected`. | |
| /** | |
| * @since C++23 | |
| */ | |
| template<typename _Er> | |
| class unexpected; | |
| /// Exception thrown by std::expected when the value() is not present. | |
| /** | |
| * @since C++23 | |
| */ | |
| template<typename _Er> | |
| class bad_expected_access; | |
| #if __cpp_lib_constexpr_exceptions >= 202502L | |
| #define _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS constexpr | |
| #else | |
| #define _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS | |
| #endif | |
| template<> | |
| class bad_expected_access<void> : public exception | |
| { | |
| protected: | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS bad_expected_access() noexcept { } | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS | |
| bad_expected_access(const bad_expected_access&) noexcept = default; | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS | |
| bad_expected_access(bad_expected_access&&) noexcept = default; | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS | |
| bad_expected_access& operator=(const bad_expected_access&) noexcept = default; | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS | |
| bad_expected_access& operator=(bad_expected_access&&) noexcept = default; | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS | |
| ~bad_expected_access() = default; | |
| public: | |
| [[nodiscard]] | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS const char* | |
| what() const noexcept override | |
| { return "bad access to std::expected without expected value"; } | |
| }; | |
| template<typename _Er> | |
| class bad_expected_access : public bad_expected_access<void> { | |
| public: | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS explicit | |
| bad_expected_access(_Er __e) : _M_unex(std::move(__e)) { } | |
| // XXX const char* what() const noexcept override; | |
| [[nodiscard]] | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS _Er& | |
| error() & noexcept | |
| { return _M_unex; } | |
| [[nodiscard]] | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS const _Er& | |
| error() const & noexcept | |
| { return _M_unex; } | |
| [[nodiscard]] | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS _Er&& | |
| error() && noexcept | |
| { return std::move(_M_unex); } | |
| [[nodiscard]] | |
| _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS const _Er&& | |
| error() const && noexcept | |
| { return std::move(_M_unex); } | |
| private: | |
| _Er _M_unex; | |
| }; | |
| /// Tag type for constructing unexpected values in a std::expected | |
| /** | |
| * @since C++23 | |
| */ | |
| struct unexpect_t | |
| { | |
| explicit unexpect_t() = default; | |
| }; | |
| /// Tag for constructing unexpected values in a std::expected | |
| /** | |
| * @since C++23 | |
| */ | |
| inline constexpr unexpect_t unexpect{}; | |
| /// @cond undocumented | |
| namespace __expected | |
| { | |
| template<typename _Tp> | |
| constexpr bool __is_expected = false; | |
| template<typename _Tp, typename _Er> | |
| constexpr bool __is_expected<expected<_Tp, _Er>> = true; | |
| template<typename _Tp> | |
| constexpr bool __is_unexpected = false; | |
| template<typename _Tp> | |
| constexpr bool __is_unexpected<unexpected<_Tp>> = true; | |
| template<typename _Fn, typename _Tp> | |
| using __result = remove_cvref_t<invoke_result_t<_Fn&&, _Tp&&>>; | |
| template<typename _Fn, typename _Tp> | |
| using __result_xform = remove_cv_t<invoke_result_t<_Fn&&, _Tp&&>>; | |
| template<typename _Fn> | |
| using __result0 = remove_cvref_t<invoke_result_t<_Fn&&>>; | |
| template<typename _Fn> | |
| using __result0_xform = remove_cv_t<invoke_result_t<_Fn&&>>; | |
| template<typename _Er> | |
| concept __can_be_unexpected | |
| = is_object_v<_Er> && (!is_array_v<_Er>) | |
| && (!__expected::__is_unexpected<_Er>) | |
| && (!is_const_v<_Er>) && (!is_volatile_v<_Er>); | |
| // Tag types for in-place construction from an invocation result. | |
| struct __in_place_inv { }; | |
| struct __unexpect_inv { }; | |
| } | |
| /// @endcond | |
| template<typename _Er> | |
| class unexpected | |
| { | |
| static_assert( __expected::__can_be_unexpected<_Er> ); | |
| public: | |
| constexpr unexpected(const unexpected&) = default; | |
| constexpr unexpected(unexpected&&) = default; | |
| template<typename _Err = _Er> | |
| requires (!is_same_v<remove_cvref_t<_Err>, unexpected>) | |
| && (!is_same_v<remove_cvref_t<_Err>, in_place_t>) | |
| && is_constructible_v<_Er, _Err> | |
| constexpr explicit | |
| unexpected(_Err&& __e) | |
| noexcept(is_nothrow_constructible_v<_Er, _Err>) | |
| : _M_unex(std::forward<_Err>(__e)) | |
| { } | |
| template<typename... _Args> | |
| requires is_constructible_v<_Er, _Args...> | |
| constexpr explicit | |
| unexpected(in_place_t, _Args&&... __args) | |
| noexcept(is_nothrow_constructible_v<_Er, _Args...>) | |
| : _M_unex(std::forward<_Args>(__args)...) | |
| { } | |
| template<typename _Up, typename... _Args> | |
| requires is_constructible_v<_Er, initializer_list<_Up>&, _Args...> | |
| constexpr explicit | |
| unexpected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) | |
| noexcept(is_nothrow_constructible_v<_Er, initializer_list<_Up>&, | |
| _Args...>) | |
| : _M_unex(__il, std::forward<_Args>(__args)...) | |
| { } | |
| constexpr unexpected& operator=(const unexpected&) = default; | |
| constexpr unexpected& operator=(unexpected&&) = default; | |
| [[nodiscard]] | |
| constexpr const _Er& | |
| error() const & noexcept { return _M_unex; } | |
| [[nodiscard]] | |
| constexpr _Er& | |
| error() & noexcept { return _M_unex; } | |
| [[nodiscard]] | |
| constexpr const _Er&& | |
| error() const && noexcept { return std::move(_M_unex); } | |
| [[nodiscard]] | |
| constexpr _Er&& | |
| error() && noexcept { return std::move(_M_unex); } | |
| constexpr void | |
| swap(unexpected& __other) noexcept(is_nothrow_swappable_v<_Er>) | |
| requires is_swappable_v<_Er> | |
| { | |
| using std::swap; | |
| swap(_M_unex, __other._M_unex); | |
| } | |
| template<typename _Err> | |
| [[nodiscard]] | |
| friend constexpr bool | |
| operator==(const unexpected& __x, const unexpected<_Err>& __y) | |
| { return __x._M_unex == __y.error(); } | |
| friend constexpr void | |
| swap(unexpected& __x, unexpected& __y) noexcept(noexcept(__x.swap(__y))) | |
| requires is_swappable_v<_Er> | |
| { __x.swap(__y); } | |
| private: | |
| _Er _M_unex; | |
| }; | |
| template<typename _Er> unexpected(_Er) -> unexpected<_Er>; | |
| /// @cond undocumented | |
| namespace __expected | |
| { | |
| template<typename _Tp> | |
| struct _Guard | |
| { | |
| static_assert( is_nothrow_move_constructible_v<_Tp> ); | |
| constexpr explicit | |
| _Guard(_Tp& __x) | |
| : _M_guarded(__builtin_addressof(__x)), _M_tmp(std::move(__x)) // nothrow | |
| { std::destroy_at(_M_guarded); } | |
| constexpr | |
| ~_Guard() | |
| { | |
| if (_M_guarded) [[unlikely]] | |
| std::construct_at(_M_guarded, std::move(_M_tmp)); | |
| } | |
| _Guard(const _Guard&) = delete; | |
| _Guard& operator=(const _Guard&) = delete; | |
| constexpr _Tp&& | |
| release() noexcept | |
| { | |
| _M_guarded = nullptr; | |
| return std::move(_M_tmp); | |
| } | |
| private: | |
| _Tp* _M_guarded; | |
| _Tp _M_tmp; | |
| }; | |
| // reinit-expected helper from [expected.object.assign] | |
| template<typename _Tp, typename _Up, typename _Vp> | |
| constexpr void | |
| __reinit(_Tp* __newval, _Up* __oldval, _Vp&& __arg) | |
| noexcept(is_nothrow_constructible_v<_Tp, _Vp>) | |
| { | |
| if constexpr (is_nothrow_constructible_v<_Tp, _Vp>) | |
| { | |
| std::destroy_at(__oldval); | |
| std::construct_at(__newval, std::forward<_Vp>(__arg)); | |
| } | |
| else if constexpr (is_nothrow_move_constructible_v<_Tp>) | |
| { | |
| _Tp __tmp(std::forward<_Vp>(__arg)); // might throw | |
| std::destroy_at(__oldval); | |
| std::construct_at(__newval, std::move(__tmp)); | |
| } | |
| else | |
| { | |
| _Guard<_Up> __guard(*__oldval); | |
| std::construct_at(__newval, std::forward<_Vp>(__arg)); // might throw | |
| __guard.release(); | |
| } | |
| } | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 3836. std::expected<bool, E1> conversion constructor | |
| // expected(const expected<U, G>&) should take precedence over | |
| // expected(U&&) with operator bool | |
| // If T is cv bool, remove_cvref_t<U> is not a specialization of expected. | |
| template<typename _Tp, typename _Up> | |
| concept __not_constructing_bool_from_expected | |
| = ! is_same_v<remove_cv_t<_Tp>, bool> | |
| || ! __is_expected<remove_cvref_t<_Up>>; | |
| template<typename _Tp, typename _Up = remove_cvref_t<_Tp>> | |
| concept __trivially_replaceable | |
| = is_trivially_constructible_v<_Up, _Tp> | |
| && is_trivially_assignable_v<_Up&, _Tp> | |
| && is_trivially_destructible_v<_Up>; | |
| template<typename _Tp, typename _Up = remove_cvref_t<_Tp>> | |
| concept __usable_for_assign | |
| = is_constructible_v<_Up, _Tp> && is_assignable_v<_Up&, _Tp>; | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 4026. Assignment operators of std::expected should propagate triviality | |
| template<typename _Tp> | |
| concept __usable_for_trivial_assign | |
| = __trivially_replaceable<_Tp> && __usable_for_assign<_Tp>; | |
| // For copy/move assignment to replace T with E (or vice versa) | |
| // we require at least one of them to be nothrow move constructible. | |
| template<typename _Tp, typename _Er> | |
| concept __can_reassign_type | |
| = is_nothrow_move_constructible_v<_Tp> | |
| || is_nothrow_move_constructible_v<_Er>; | |
| } | |
| /// @endcond | |
| template<typename _Tp, typename _Er> | |
| class [[nodiscard]] expected | |
| { | |
| static_assert( ! is_reference_v<_Tp> ); | |
| static_assert( ! is_function_v<_Tp> ); | |
| static_assert( ! is_same_v<remove_cv_t<_Tp>, in_place_t> ); | |
| static_assert( ! is_same_v<remove_cv_t<_Tp>, unexpect_t> ); | |
| static_assert( ! __expected::__is_unexpected<remove_cv_t<_Tp>> ); | |
| static_assert( __expected::__can_be_unexpected<_Er> ); | |
| // If T is not cv bool, converts-from-any-cvref<T, expected<U, G>> and | |
| // is_constructible<unexpected<E>, cv expected<U, G> ref-qual> are false. | |
| template<typename _Up, typename _Gr, typename _Unex = unexpected<_Er>, | |
| typename = remove_cv_t<_Tp>> | |
| static constexpr bool __cons_from_expected | |
| = __or_v<is_constructible<_Tp, expected<_Up, _Gr>&>, | |
| is_constructible<_Tp, expected<_Up, _Gr>>, | |
| is_constructible<_Tp, const expected<_Up, _Gr>&>, | |
| is_constructible<_Tp, const expected<_Up, _Gr>>, | |
| is_convertible<expected<_Up, _Gr>&, _Tp>, | |
| is_convertible<expected<_Up, _Gr>, _Tp>, | |
| is_convertible<const expected<_Up, _Gr>&, _Tp>, | |
| is_convertible<const expected<_Up, _Gr>, _Tp>, | |
| is_constructible<_Unex, expected<_Up, _Gr>&>, | |
| is_constructible<_Unex, expected<_Up, _Gr>>, | |
| is_constructible<_Unex, const expected<_Up, _Gr>&>, | |
| is_constructible<_Unex, const expected<_Up, _Gr>> | |
| >; | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // If t is cv bool, we know it can be constructed from expected<U, G>, | |
| // but we don't want to cause the expected(U&&) constructor to be used, | |
| // so we only check the is_constructible<unexpected<E>, ...> cases. | |
| template<typename _Up, typename _Gr, typename _Unex> | |
| static constexpr bool __cons_from_expected<_Up, _Gr, _Unex, bool> | |
| = __or_v<is_constructible<_Unex, expected<_Up, _Gr>&>, | |
| is_constructible<_Unex, expected<_Up, _Gr>>, | |
| is_constructible<_Unex, const expected<_Up, _Gr>&>, | |
| is_constructible<_Unex, const expected<_Up, _Gr>> | |
| >; | |
| template<typename _Up, typename _Gr> | |
| constexpr static bool __explicit_conv | |
| = __or_v<__not_<is_convertible<_Up, _Tp>>, | |
| __not_<is_convertible<_Gr, _Er>> | |
| >; | |
| template<typename _Up> | |
| static constexpr bool __same_val | |
| = is_same_v<typename _Up::value_type, _Tp>; | |
| template<typename _Up> | |
| static constexpr bool __same_err | |
| = is_same_v<typename _Up::error_type, _Er>; | |
| public: | |
| using value_type = _Tp; | |
| using error_type = _Er; | |
| using unexpected_type = unexpected<_Er>; | |
| template<typename _Up> | |
| using rebind = expected<_Up, error_type>; | |
| constexpr | |
| expected() | |
| noexcept(is_nothrow_default_constructible_v<_Tp>) | |
| requires is_default_constructible_v<_Tp> | |
| : _M_val(), _M_has_value(true) | |
| { } | |
| expected(const expected&) = default; | |
| constexpr | |
| expected(const expected& __x) | |
| noexcept(__and_v<is_nothrow_copy_constructible<_Tp>, | |
| is_nothrow_copy_constructible<_Er>>) | |
| requires is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Er> | |
| && (!is_trivially_copy_constructible_v<_Tp> | |
| || !is_trivially_copy_constructible_v<_Er>) | |
| : _M_has_value(__x._M_has_value) | |
| { | |
| if (_M_has_value) | |
| std::construct_at(__builtin_addressof(_M_val), __x._M_val); | |
| else | |
| std::construct_at(__builtin_addressof(_M_unex), __x._M_unex); | |
| } | |
| expected(expected&&) = default; | |
| constexpr | |
| expected(expected&& __x) | |
| noexcept(__and_v<is_nothrow_move_constructible<_Tp>, | |
| is_nothrow_move_constructible<_Er>>) | |
| requires is_move_constructible_v<_Tp> && is_move_constructible_v<_Er> | |
| && (!is_trivially_move_constructible_v<_Tp> | |
| || !is_trivially_move_constructible_v<_Er>) | |
| : _M_has_value(__x._M_has_value) | |
| { | |
| if (_M_has_value) | |
| std::construct_at(__builtin_addressof(_M_val), | |
| std::move(__x)._M_val); | |
| else | |
| std::construct_at(__builtin_addressof(_M_unex), | |
| std::move(__x)._M_unex); | |
| } | |
| template<typename _Up, typename _Gr> | |
| requires is_constructible_v<_Tp, const _Up&> | |
| && is_constructible_v<_Er, const _Gr&> | |
| && (!__cons_from_expected<_Up, _Gr>) | |
| constexpr explicit(__explicit_conv<const _Up&, const _Gr&>) | |
| expected(const expected<_Up, _Gr>& __x) | |
| noexcept(__and_v<is_nothrow_constructible<_Tp, const _Up&>, | |
| is_nothrow_constructible<_Er, const _Gr&>>) | |
| : _M_has_value(__x._M_has_value) | |
| { | |
| if (_M_has_value) | |
| std::construct_at(__builtin_addressof(_M_val), __x._M_val); | |
| else | |
| std::construct_at(__builtin_addressof(_M_unex), __x._M_unex); | |
| } | |
| template<typename _Up, typename _Gr> | |
| requires is_constructible_v<_Tp, _Up> | |
| && is_constructible_v<_Er, _Gr> | |
| && (!__cons_from_expected<_Up, _Gr>) | |
| constexpr explicit(__explicit_conv<_Up, _Gr>) | |
| expected(expected<_Up, _Gr>&& __x) | |
| noexcept(__and_v<is_nothrow_constructible<_Tp, _Up>, | |
| is_nothrow_constructible<_Er, _Gr>>) | |
| : _M_has_value(__x._M_has_value) | |
| { | |
| if (_M_has_value) | |
| std::construct_at(__builtin_addressof(_M_val), | |
| std::move(__x)._M_val); | |
| else | |
| std::construct_at(__builtin_addressof(_M_unex), | |
| std::move(__x)._M_unex); | |
| } | |
| template<typename _Up = remove_cv_t<_Tp>> | |
| requires (!is_same_v<remove_cvref_t<_Up>, expected>) | |
| && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) | |
| && (!is_same_v<remove_cvref_t<_Up>, unexpect_t>) | |
| && is_constructible_v<_Tp, _Up> | |
| && (!__expected::__is_unexpected<remove_cvref_t<_Up>>) | |
| && __expected::__not_constructing_bool_from_expected<_Tp, _Up> | |
| constexpr explicit(!is_convertible_v<_Up, _Tp>) | |
| expected(_Up&& __v) | |
| noexcept(is_nothrow_constructible_v<_Tp, _Up>) | |
| : _M_val(std::forward<_Up>(__v)), _M_has_value(true) | |
| { } | |
| template<typename _Gr = _Er> | |
| requires is_constructible_v<_Er, const _Gr&> | |
| constexpr explicit(!is_convertible_v<const _Gr&, _Er>) | |
| expected(const unexpected<_Gr>& __u) | |
| noexcept(is_nothrow_constructible_v<_Er, const _Gr&>) | |
| : _M_unex(__u.error()), _M_has_value(false) | |
| { } | |
| template<typename _Gr = _Er> | |
| requires is_constructible_v<_Er, _Gr> | |
| constexpr explicit(!is_convertible_v<_Gr, _Er>) | |
| expected(unexpected<_Gr>&& __u) | |
| noexcept(is_nothrow_constructible_v<_Er, _Gr>) | |
| : _M_unex(std::move(__u).error()), _M_has_value(false) | |
| { } | |
| template<typename... _Args> | |
| requires is_constructible_v<_Tp, _Args...> | |
| constexpr explicit | |
| expected(in_place_t, _Args&&... __args) | |
| noexcept(is_nothrow_constructible_v<_Tp, _Args...>) | |
| : _M_val(std::forward<_Args>(__args)...), _M_has_value(true) | |
| { } | |
| template<typename _Up, typename... _Args> | |
| requires is_constructible_v<_Tp, initializer_list<_Up>&, _Args...> | |
| constexpr explicit | |
| expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) | |
| noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, | |
| _Args...>) | |
| : _M_val(__il, std::forward<_Args>(__args)...), _M_has_value(true) | |
| { } | |
| template<typename... _Args> | |
| requires is_constructible_v<_Er, _Args...> | |
| constexpr explicit | |
| expected(unexpect_t, _Args&&... __args) | |
| noexcept(is_nothrow_constructible_v<_Er, _Args...>) | |
| : _M_unex(std::forward<_Args>(__args)...), _M_has_value(false) | |
| { } | |
| template<typename _Up, typename... _Args> | |
| requires is_constructible_v<_Er, initializer_list<_Up>&, _Args...> | |
| constexpr explicit | |
| expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) | |
| noexcept(is_nothrow_constructible_v<_Er, initializer_list<_Up>&, | |
| _Args...>) | |
| : _M_unex(__il, std::forward<_Args>(__args)...), _M_has_value(false) | |
| { } | |
| constexpr ~expected() = default; | |
| constexpr ~expected() | |
| requires (!is_trivially_destructible_v<_Tp>) | |
| || (!is_trivially_destructible_v<_Er>) | |
| { | |
| if (_M_has_value) | |
| std::destroy_at(__builtin_addressof(_M_val)); | |
| else | |
| std::destroy_at(__builtin_addressof(_M_unex)); | |
| } | |
| // assignment | |
| // Deleted copy assignment, when constraints not met for other overloads | |
| expected& operator=(const expected&) = delete; | |
| // Trivial copy assignment | |
| expected& | |
| operator=(const expected&) | |
| noexcept(__and_v<is_nothrow_copy_constructible<_Tp>, | |
| is_nothrow_copy_constructible<_Er>, | |
| is_nothrow_copy_assignable<_Tp>, | |
| is_nothrow_copy_assignable<_Er>>) | |
| requires __expected::__usable_for_trivial_assign<const _Tp&> | |
| && __expected::__usable_for_trivial_assign<const _Er&> | |
| && __expected::__can_reassign_type<_Tp, _Er> | |
| = default; | |
| // Non-trivial copy assignment | |
| constexpr expected& | |
| operator=(const expected& __x) | |
| noexcept(__and_v<is_nothrow_copy_constructible<_Tp>, | |
| is_nothrow_copy_constructible<_Er>, | |
| is_nothrow_copy_assignable<_Tp>, | |
| is_nothrow_copy_assignable<_Er>>) | |
| requires __expected::__usable_for_assign<const _Tp&> | |
| && __expected::__usable_for_assign<const _Er&> | |
| && __expected::__can_reassign_type<_Tp, _Er> | |
| { | |
| if (__x._M_has_value) | |
| this->_M_assign_val(__x._M_val); | |
| else | |
| this->_M_assign_unex(__x._M_unex); | |
| return *this; | |
| } | |
| // Trivial move assignment | |
| expected& | |
| operator=(expected&&) | |
| noexcept(__and_v<is_nothrow_move_constructible<_Tp>, | |
| is_nothrow_move_constructible<_Er>, | |
| is_nothrow_move_assignable<_Tp>, | |
| is_nothrow_move_assignable<_Er>>) | |
| requires __expected::__usable_for_trivial_assign<_Tp&&> | |
| && __expected::__usable_for_trivial_assign<_Er&&> | |
| && __expected::__can_reassign_type<_Tp, _Er> | |
| = default; | |
| // Non-trivial move assignment | |
| constexpr expected& | |
| operator=(expected&& __x) | |
| noexcept(__and_v<is_nothrow_move_constructible<_Tp>, | |
| is_nothrow_move_constructible<_Er>, | |
| is_nothrow_move_assignable<_Tp>, | |
| is_nothrow_move_assignable<_Er>>) | |
| requires __expected::__usable_for_assign<_Tp&&> | |
| && __expected::__usable_for_assign<_Er&&> | |
| && __expected::__can_reassign_type<_Tp, _Er> | |
| { | |
| if (__x._M_has_value) | |
| _M_assign_val(std::move(__x._M_val)); | |
| else | |
| _M_assign_unex(std::move(__x._M_unex)); | |
| return *this; | |
| } | |
| template<typename _Up = remove_cv_t<_Tp>> | |
| requires (!is_same_v<expected, remove_cvref_t<_Up>>) | |
| && (!__expected::__is_unexpected<remove_cvref_t<_Up>>) | |
| && is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up> | |
| && (is_nothrow_constructible_v<_Tp, _Up> | |
| || is_nothrow_move_constructible_v<_Tp> | |
| || is_nothrow_move_constructible_v<_Er>) | |
| constexpr expected& | |
| operator=(_Up&& __v) | |
| { | |
| _M_assign_val(std::forward<_Up>(__v)); | |
| return *this; | |
| } | |
| template<typename _Gr> | |
| requires is_constructible_v<_Er, const _Gr&> | |
| && is_assignable_v<_Er&, const _Gr&> | |
| && (is_nothrow_constructible_v<_Er, const _Gr&> | |
| || is_nothrow_move_constructible_v<_Tp> | |
| || is_nothrow_move_constructible_v<_Er>) | |
| constexpr expected& | |
| operator=(const unexpected<_Gr>& __e) | |
| { | |
| _M_assign_unex(__e.error()); | |
| return *this; | |
| } | |
| template<typename _Gr> | |
| requires is_constructible_v<_Er, _Gr> | |
| && is_assignable_v<_Er&, _Gr> | |
| && (is_nothrow_constructible_v<_Er, _Gr> | |
| || is_nothrow_move_constructible_v<_Tp> | |
| || is_nothrow_move_constructible_v<_Er>) | |
| constexpr expected& | |
| operator=(unexpected<_Gr>&& __e) | |
| { | |
| _M_assign_unex(std::move(__e).error()); | |
| return *this; | |
| } | |
| // modifiers | |
| template<typename... _Args> | |
| requires is_nothrow_constructible_v<_Tp, _Args...> | |
| constexpr _Tp& | |
| emplace(_Args&&... __args) noexcept | |
| { | |
| if (_M_has_value) | |
| std::destroy_at(__builtin_addressof(_M_val)); | |
| else | |
| { | |
| std::destroy_at(__builtin_addressof(_M_unex)); | |
| _M_has_value = true; | |
| } | |
| std::construct_at(__builtin_addressof(_M_val), | |
| std::forward<_Args>(__args)...); | |
| return _M_val; | |
| } | |
| template<typename _Up, typename... _Args> | |
| requires is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, | |
| _Args...> | |
| constexpr _Tp& | |
| emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept | |
| { | |
| if (_M_has_value) | |
| std::destroy_at(__builtin_addressof(_M_val)); | |
| else | |
| { | |
| std::destroy_at(__builtin_addressof(_M_unex)); | |
| _M_has_value = true; | |
| } | |
| std::construct_at(__builtin_addressof(_M_val), | |
| __il, std::forward<_Args>(__args)...); | |
| return _M_val; | |
| } | |
| // swap | |
| constexpr void | |
| swap(expected& __x) | |
| noexcept(__and_v<is_nothrow_move_constructible<_Tp>, | |
| is_nothrow_move_constructible<_Er>, | |
| is_nothrow_swappable<_Tp&>, | |
| is_nothrow_swappable<_Er&>>) | |
| requires is_swappable_v<_Tp> && is_swappable_v<_Er> | |
| && is_move_constructible_v<_Tp> | |
| && is_move_constructible_v<_Er> | |
| && (is_nothrow_move_constructible_v<_Tp> | |
| || is_nothrow_move_constructible_v<_Er>) | |
| { | |
| if (_M_has_value) | |
| { | |
| if (__x._M_has_value) | |
| { | |
| using std::swap; | |
| swap(_M_val, __x._M_val); | |
| } | |
| else | |
| this->_M_swap_val_unex(__x); | |
| } | |
| else | |
| { | |
| if (__x._M_has_value) | |
| __x._M_swap_val_unex(*this); | |
| else | |
| { | |
| using std::swap; | |
| swap(_M_unex, __x._M_unex); | |
| } | |
| } | |
| } | |
| // observers | |
| [[nodiscard]] | |
| constexpr const _Tp* | |
| operator->() const noexcept | |
| { | |
| __glibcxx_assert(_M_has_value); | |
| return __builtin_addressof(_M_val); | |
| } | |
| [[nodiscard]] | |
| constexpr _Tp* | |
| operator->() noexcept | |
| { | |
| __glibcxx_assert(_M_has_value); | |
| return __builtin_addressof(_M_val); | |
| } | |
| [[nodiscard]] | |
| constexpr const _Tp& | |
| operator*() const & noexcept | |
| { | |
| __glibcxx_assert(_M_has_value); | |
| return _M_val; | |
| } | |
| [[nodiscard]] | |
| constexpr _Tp& | |
| operator*() & noexcept | |
| { | |
| __glibcxx_assert(_M_has_value); | |
| return _M_val; | |
| } | |
| [[nodiscard]] | |
| constexpr const _Tp&& | |
| operator*() const && noexcept | |
| { | |
| __glibcxx_assert(_M_has_value); | |
| return std::move(_M_val); | |
| } | |
| [[nodiscard]] | |
| constexpr _Tp&& | |
| operator*() && noexcept | |
| { | |
| __glibcxx_assert(_M_has_value); | |
| return std::move(_M_val); | |
| } | |
| [[nodiscard]] | |
| constexpr explicit | |
| operator bool() const noexcept { return _M_has_value; } | |
| [[nodiscard]] | |
| constexpr bool has_value() const noexcept { return _M_has_value; } | |
| constexpr const _Tp& | |
| value() const & | |
| { | |
| static_assert( is_copy_constructible_v<_Er> ); | |
| if (_M_has_value) [[likely]] | |
| return _M_val; | |
| _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(_M_unex)); | |
| } | |
| constexpr _Tp& | |
| value() & | |
| { | |
| static_assert( is_copy_constructible_v<_Er> ); | |
| if (_M_has_value) [[likely]] | |
| return _M_val; | |
| const auto& __unex = _M_unex; | |
| _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(__unex)); | |
| } | |
| constexpr const _Tp&& | |
| value() const && | |
| { | |
| static_assert( is_copy_constructible_v<_Er> ); | |
| static_assert( is_constructible_v<_Er, const _Er&&> ); | |
| if (_M_has_value) [[likely]] | |
| return std::move(_M_val); | |
| _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex))); | |
| } | |
| constexpr _Tp&& | |
| value() && | |
| { | |
| static_assert( is_copy_constructible_v<_Er> ); | |
| static_assert( is_constructible_v<_Er, _Er&&> ); | |
| if (_M_has_value) [[likely]] | |
| return std::move(_M_val); | |
| _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex))); | |
| } | |
| constexpr const _Er& | |
| error() const & noexcept | |
| { | |
| __glibcxx_assert(!_M_has_value); | |
| return _M_unex; | |
| } | |
| constexpr _Er& | |
| error() & noexcept | |
| { | |
| __glibcxx_assert(!_M_has_value); | |
| return _M_unex; | |
| } | |
| constexpr const _Er&& | |
| error() const && noexcept | |
| { | |
| __glibcxx_assert(!_M_has_value); | |
| return std::move(_M_unex); | |
| } | |
| constexpr _Er&& | |
| error() && noexcept | |
| { | |
| __glibcxx_assert(!_M_has_value); | |
| return std::move(_M_unex); | |
| } | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 4406. value_or return statement is inconsistent with Mandates | |
| template<typename _Up = remove_cv_t<_Tp>> | |
| constexpr remove_cv_t<_Tp> | |
| value_or(_Up&& __v) const & | |
| noexcept(__and_v<is_nothrow_copy_constructible<_Tp>, | |
| is_nothrow_convertible<_Up, _Tp>>) | |
| { | |
| using _Xp = remove_cv_t<_Tp>; | |
| static_assert( is_convertible_v<const _Tp&, _Xp> ); | |
| static_assert( is_convertible_v<_Up, _Tp> ); | |
| if (_M_has_value) | |
| return _M_val; | |
| return std::forward<_Up>(__v); | |
| } | |
| template<typename _Up = remove_cv_t<_Tp>> | |
| constexpr remove_cv_t<_Tp> | |
| value_or(_Up&& __v) && | |
| noexcept(__and_v<is_nothrow_move_constructible<_Tp>, | |
| is_nothrow_convertible<_Up, _Tp>>) | |
| { | |
| using _Xp = remove_cv_t<_Tp>; | |
| static_assert( is_convertible_v<_Tp, _Xp> ); | |
| static_assert( is_convertible_v<_Up, _Xp> ); | |
| if (_M_has_value) | |
| return std::move(_M_val); | |
| return std::forward<_Up>(__v); | |
| } | |
| template<typename _Gr = _Er> | |
| constexpr _Er | |
| error_or(_Gr&& __e) const& | |
| { | |
| static_assert( is_copy_constructible_v<_Er> ); | |
| static_assert( is_convertible_v<_Gr, _Er> ); | |
| if (_M_has_value) | |
| return std::forward<_Gr>(__e); | |
| return _M_unex; | |
| } | |
| template<typename _Gr = _Er> | |
| constexpr _Er | |
| error_or(_Gr&& __e) && | |
| { | |
| static_assert( is_move_constructible_v<_Er> ); | |
| static_assert( is_convertible_v<_Gr, _Er> ); | |
| if (_M_has_value) | |
| return std::forward<_Gr>(__e); | |
| return std::move(_M_unex); | |
| } | |
| // monadic operations | |
| template<typename _Fn> requires is_constructible_v<_Er, _Er&> | |
| constexpr auto | |
| and_then(_Fn&& __f) & | |
| { | |
| using _Up = __expected::__result<_Fn, _Tp&>; | |
| static_assert(__expected::__is_expected<_Up>, | |
| "the function passed to std::expected<T, E>::and_then " | |
| "must return a std::expected"); | |
| static_assert(is_same_v<typename _Up::error_type, _Er>, | |
| "the function passed to std::expected<T, E>::and_then " | |
| "must return a std::expected with the same error_type"); | |
| if (has_value()) | |
| return std::__invoke(std::forward<_Fn>(__f), _M_val); | |
| else | |
| return _Up(unexpect, _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, const _Er&> | |
| constexpr auto | |
| and_then(_Fn&& __f) const & | |
| { | |
| using _Up = __expected::__result<_Fn, const _Tp&>; | |
| static_assert(__expected::__is_expected<_Up>, | |
| "the function passed to std::expected<T, E>::and_then " | |
| "must return a std::expected"); | |
| static_assert(is_same_v<typename _Up::error_type, _Er>, | |
| "the function passed to std::expected<T, E>::and_then " | |
| "must return a std::expected with the same error_type"); | |
| if (has_value()) | |
| return std::__invoke(std::forward<_Fn>(__f), _M_val); | |
| else | |
| return _Up(unexpect, _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, _Er> | |
| constexpr auto | |
| and_then(_Fn&& __f) && | |
| { | |
| using _Up = __expected::__result<_Fn, _Tp&&>; | |
| static_assert(__expected::__is_expected<_Up>, | |
| "the function passed to std::expected<T, E>::and_then " | |
| "must return a std::expected"); | |
| static_assert(is_same_v<typename _Up::error_type, _Er>, | |
| "the function passed to std::expected<T, E>::and_then " | |
| "must return a std::expected with the same error_type"); | |
| if (has_value()) | |
| return std::__invoke(std::forward<_Fn>(__f), std::move(_M_val)); | |
| else | |
| return _Up(unexpect, std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, const _Er> | |
| constexpr auto | |
| and_then(_Fn&& __f) const && | |
| { | |
| using _Up = __expected::__result<_Fn, const _Tp&&>; | |
| static_assert(__expected::__is_expected<_Up>, | |
| "the function passed to std::expected<T, E>::and_then " | |
| "must return a std::expected"); | |
| static_assert(is_same_v<typename _Up::error_type, _Er>, | |
| "the function passed to std::expected<T, E>::and_then " | |
| "must return a std::expected with the same error_type"); | |
| if (has_value()) | |
| return std::__invoke(std::forward<_Fn>(__f), std::move(_M_val)); | |
| else | |
| return _Up(unexpect, std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Tp, _Tp&> | |
| constexpr auto | |
| or_else(_Fn&& __f) & | |
| { | |
| using _Gr = __expected::__result<_Fn, _Er&>; | |
| static_assert(__expected::__is_expected<_Gr>, | |
| "the function passed to std::expected<T, E>::or_else " | |
| "must return a std::expected"); | |
| static_assert(is_same_v<typename _Gr::value_type, _Tp>, | |
| "the function passed to std::expected<T, E>::or_else " | |
| "must return a std::expected with the same value_type"); | |
| if (has_value()) | |
| return _Gr(in_place, _M_val); | |
| else | |
| return std::__invoke(std::forward<_Fn>(__f), _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Tp, const _Tp&> | |
| constexpr auto | |
| or_else(_Fn&& __f) const & | |
| { | |
| using _Gr = __expected::__result<_Fn, const _Er&>; | |
| static_assert(__expected::__is_expected<_Gr>, | |
| "the function passed to std::expected<T, E>::or_else " | |
| "must return a std::expected"); | |
| static_assert(is_same_v<typename _Gr::value_type, _Tp>, | |
| "the function passed to std::expected<T, E>::or_else " | |
| "must return a std::expected with the same value_type"); | |
| if (has_value()) | |
| return _Gr(in_place, _M_val); | |
| else | |
| return std::__invoke(std::forward<_Fn>(__f), _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Tp, _Tp> | |
| constexpr auto | |
| or_else(_Fn&& __f) && | |
| { | |
| using _Gr = __expected::__result<_Fn, _Er&&>; | |
| static_assert(__expected::__is_expected<_Gr>, | |
| "the function passed to std::expected<T, E>::or_else " | |
| "must return a std::expected"); | |
| static_assert(is_same_v<typename _Gr::value_type, _Tp>, | |
| "the function passed to std::expected<T, E>::or_else " | |
| "must return a std::expected with the same value_type"); | |
| if (has_value()) | |
| return _Gr(in_place, std::move(_M_val)); | |
| else | |
| return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Tp, const _Tp> | |
| constexpr auto | |
| or_else(_Fn&& __f) const && | |
| { | |
| using _Gr = __expected::__result<_Fn, const _Er&&>; | |
| static_assert(__expected::__is_expected<_Gr>, | |
| "the function passed to std::expected<T, E>::or_else " | |
| "must return a std::expected"); | |
| static_assert(is_same_v<typename _Gr::value_type, _Tp>, | |
| "the function passed to std::expected<T, E>::or_else " | |
| "must return a std::expected with the same value_type"); | |
| if (has_value()) | |
| return _Gr(in_place, std::move(_M_val)); | |
| else | |
| return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, _Er&> | |
| constexpr auto | |
| transform(_Fn&& __f) & | |
| { | |
| using _Up = __expected::__result_xform<_Fn, _Tp&>; | |
| using _Res = expected<_Up, _Er>; | |
| if (has_value()) | |
| return _Res(__in_place_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| _M_val); | |
| }); | |
| else | |
| return _Res(unexpect, _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, const _Er&> | |
| constexpr auto | |
| transform(_Fn&& __f) const & | |
| { | |
| using _Up = __expected::__result_xform<_Fn, const _Tp&>; | |
| using _Res = expected<_Up, _Er>; | |
| if (has_value()) | |
| return _Res(__in_place_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| _M_val); | |
| }); | |
| else | |
| return _Res(unexpect, _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, _Er> | |
| constexpr auto | |
| transform(_Fn&& __f) && | |
| { | |
| using _Up = __expected::__result_xform<_Fn, _Tp>; | |
| using _Res = expected<_Up, _Er>; | |
| if (has_value()) | |
| return _Res(__in_place_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| std::move(_M_val)); | |
| }); | |
| else | |
| return _Res(unexpect, std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, const _Er> | |
| constexpr auto | |
| transform(_Fn&& __f) const && | |
| { | |
| using _Up = __expected::__result_xform<_Fn, const _Tp>; | |
| using _Res = expected<_Up, _Er>; | |
| if (has_value()) | |
| return _Res(__in_place_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| std::move(_M_val)); | |
| }); | |
| else | |
| return _Res(unexpect, std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Tp, _Tp&> | |
| constexpr auto | |
| transform_error(_Fn&& __f) & | |
| { | |
| using _Gr = __expected::__result_xform<_Fn, _Er&>; | |
| using _Res = expected<_Tp, _Gr>; | |
| if (has_value()) | |
| return _Res(in_place, _M_val); | |
| else | |
| return _Res(__unexpect_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| _M_unex); | |
| }); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Tp, const _Tp&> | |
| constexpr auto | |
| transform_error(_Fn&& __f) const & | |
| { | |
| using _Gr = __expected::__result_xform<_Fn, const _Er&>; | |
| using _Res = expected<_Tp, _Gr>; | |
| if (has_value()) | |
| return _Res(in_place, _M_val); | |
| else | |
| return _Res(__unexpect_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| _M_unex); | |
| }); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Tp, _Tp> | |
| constexpr auto | |
| transform_error(_Fn&& __f) && | |
| { | |
| using _Gr = __expected::__result_xform<_Fn, _Er&&>; | |
| using _Res = expected<_Tp, _Gr>; | |
| if (has_value()) | |
| return _Res(in_place, std::move(_M_val)); | |
| else | |
| return _Res(__unexpect_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| std::move(_M_unex)); | |
| }); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Tp, const _Tp> | |
| constexpr auto | |
| transform_error(_Fn&& __f) const && | |
| { | |
| using _Gr = __expected::__result_xform<_Fn, const _Er&&>; | |
| using _Res = expected<_Tp, _Gr>; | |
| if (has_value()) | |
| return _Res(in_place, std::move(_M_val)); | |
| else | |
| return _Res(__unexpect_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| std::move(_M_unex)); | |
| }); | |
| } | |
| // equality operators | |
| template<typename _Up, typename _Er2> | |
| requires (!is_void_v<_Up>) | |
| && requires (const _Tp& __t, const _Up& __u, | |
| const _Er& __e, const _Er2& __e2) { | |
| { __t == __u } -> convertible_to<bool>; | |
| { __e == __e2 } -> convertible_to<bool>; | |
| } | |
| [[nodiscard]] | |
| friend constexpr bool | |
| operator==(const expected& __x, const expected<_Up, _Er2>& __y) | |
| noexcept(noexcept(bool(*__x == *__y)) | |
| && noexcept(bool(__x.error() == __y.error()))) | |
| { | |
| if (__x.has_value() != __y.has_value()) | |
| return false; | |
| if (__x.has_value()) | |
| return *__x == *__y; | |
| return __x.error() == __y.error(); | |
| } | |
| template<typename _Up, same_as<_Tp> _Vp> | |
| requires (!__expected::__is_expected<_Up>) | |
| && requires (const _Tp& __t, const _Up& __u) { | |
| { __t == __u } -> convertible_to<bool>; | |
| } | |
| [[nodiscard]] | |
| friend constexpr bool | |
| operator==(const expected<_Vp, _Er>& __x, const _Up& __v) | |
| noexcept(noexcept(bool(*__x == __v))) | |
| { | |
| if (__x.has_value()) | |
| return *__x == __v; | |
| return false; | |
| } | |
| template<typename _Er2> | |
| requires requires (const _Er& __e, const _Er2& __e2) { | |
| { __e == __e2 } -> convertible_to<bool>; | |
| } | |
| [[nodiscard]] | |
| friend constexpr bool | |
| operator==(const expected& __x, const unexpected<_Er2>& __e) | |
| noexcept(noexcept(bool(__x.error() == __e.error()))) | |
| { | |
| if (!__x.has_value()) | |
| return __x.error() == __e.error(); | |
| return false; | |
| } | |
| friend constexpr void | |
| swap(expected& __x, expected& __y) | |
| noexcept(noexcept(__x.swap(__y))) | |
| requires requires {__x.swap(__y);} | |
| { __x.swap(__y); } | |
| private: | |
| template<typename, typename> friend class expected; | |
| template<typename _Vp> | |
| constexpr void | |
| _M_assign_val(_Vp&& __v) | |
| { | |
| if (_M_has_value) | |
| _M_val = std::forward<_Vp>(__v); | |
| else | |
| { | |
| __expected::__reinit(__builtin_addressof(_M_val), | |
| __builtin_addressof(_M_unex), | |
| std::forward<_Vp>(__v)); | |
| _M_has_value = true; | |
| } | |
| } | |
| template<typename _Vp> | |
| constexpr void | |
| _M_assign_unex(_Vp&& __v) | |
| { | |
| if (_M_has_value) | |
| { | |
| __expected::__reinit(__builtin_addressof(_M_unex), | |
| __builtin_addressof(_M_val), | |
| std::forward<_Vp>(__v)); | |
| _M_has_value = false; | |
| } | |
| else | |
| _M_unex = std::forward<_Vp>(__v); | |
| } | |
| // Swap two expected objects when only one has a value. | |
| // Precondition: this->_M_has_value && !__rhs._M_has_value | |
| constexpr void | |
| _M_swap_val_unex(expected& __rhs) | |
| noexcept(__and_v<is_nothrow_move_constructible<_Er>, | |
| is_nothrow_move_constructible<_Tp>>) | |
| { | |
| if constexpr (is_nothrow_move_constructible_v<_Er>) | |
| { | |
| __expected::_Guard<_Er> __guard(__rhs._M_unex); | |
| std::construct_at(__builtin_addressof(__rhs._M_val), | |
| std::move(_M_val)); // might throw | |
| __rhs._M_has_value = true; | |
| std::destroy_at(__builtin_addressof(_M_val)); | |
| std::construct_at(__builtin_addressof(_M_unex), | |
| __guard.release()); | |
| _M_has_value = false; | |
| } | |
| else | |
| { | |
| __expected::_Guard<_Tp> __guard(_M_val); | |
| std::construct_at(__builtin_addressof(_M_unex), | |
| std::move(__rhs._M_unex)); // might throw | |
| _M_has_value = false; | |
| std::destroy_at(__builtin_addressof(__rhs._M_unex)); | |
| std::construct_at(__builtin_addressof(__rhs._M_val), | |
| __guard.release()); | |
| __rhs._M_has_value = true; | |
| } | |
| } | |
| using __in_place_inv = __expected::__in_place_inv; | |
| using __unexpect_inv = __expected::__unexpect_inv; | |
| template<typename _Fn> | |
| explicit constexpr | |
| expected(__in_place_inv, _Fn&& __fn) | |
| : _M_val(std::forward<_Fn>(__fn)()), _M_has_value(true) | |
| { } | |
| template<typename _Fn> | |
| explicit constexpr | |
| expected(__unexpect_inv, _Fn&& __fn) | |
| : _M_unex(std::forward<_Fn>(__fn)()), _M_has_value(false) | |
| { } | |
| union { | |
| remove_cv_t<_Tp> _M_val; | |
| _Er _M_unex; | |
| }; | |
| bool _M_has_value; | |
| }; | |
| // Partial specialization for std::expected<cv void, E> | |
| template<typename _Tp, typename _Er> requires is_void_v<_Tp> | |
| class [[nodiscard]] expected<_Tp, _Er> | |
| { | |
| static_assert( __expected::__can_be_unexpected<_Er> ); | |
| template<typename _Up, typename _Err, typename _Unex = unexpected<_Er>> | |
| static constexpr bool __cons_from_expected | |
| = __or_v<is_constructible<_Unex, expected<_Up, _Err>&>, | |
| is_constructible<_Unex, expected<_Up, _Err>>, | |
| is_constructible<_Unex, const expected<_Up, _Err>&>, | |
| is_constructible<_Unex, const expected<_Up, _Err>> | |
| >; | |
| template<typename _Up> | |
| static constexpr bool __same_val | |
| = is_same_v<typename _Up::value_type, _Tp>; | |
| template<typename _Up> | |
| static constexpr bool __same_err | |
| = is_same_v<typename _Up::error_type, _Er>; | |
| public: | |
| using value_type = _Tp; | |
| using error_type = _Er; | |
| using unexpected_type = unexpected<_Er>; | |
| template<typename _Up> | |
| using rebind = expected<_Up, error_type>; | |
| constexpr | |
| expected() noexcept | |
| : _M_void(), _M_has_value(true) | |
| { } | |
| expected(const expected&) = default; | |
| constexpr | |
| expected(const expected& __x) | |
| noexcept(is_nothrow_copy_constructible_v<_Er>) | |
| requires is_copy_constructible_v<_Er> | |
| && (!is_trivially_copy_constructible_v<_Er>) | |
| : _M_void(), _M_has_value(__x._M_has_value) | |
| { | |
| if (!_M_has_value) | |
| std::construct_at(__builtin_addressof(_M_unex), __x._M_unex); | |
| } | |
| expected(expected&&) = default; | |
| constexpr | |
| expected(expected&& __x) | |
| noexcept(is_nothrow_move_constructible_v<_Er>) | |
| requires is_move_constructible_v<_Er> | |
| && (!is_trivially_move_constructible_v<_Er>) | |
| : _M_void(), _M_has_value(__x._M_has_value) | |
| { | |
| if (!_M_has_value) | |
| std::construct_at(__builtin_addressof(_M_unex), | |
| std::move(__x)._M_unex); | |
| } | |
| template<typename _Up, typename _Gr> | |
| requires is_void_v<_Up> | |
| && is_constructible_v<_Er, const _Gr&> | |
| && (!__cons_from_expected<_Up, _Gr>) | |
| constexpr explicit(!is_convertible_v<const _Gr&, _Er>) | |
| expected(const expected<_Up, _Gr>& __x) | |
| noexcept(is_nothrow_constructible_v<_Er, const _Gr&>) | |
| : _M_void(), _M_has_value(__x._M_has_value) | |
| { | |
| if (!_M_has_value) | |
| std::construct_at(__builtin_addressof(_M_unex), __x._M_unex); | |
| } | |
| template<typename _Up, typename _Gr> | |
| requires is_void_v<_Up> | |
| && is_constructible_v<_Er, _Gr> | |
| && (!__cons_from_expected<_Up, _Gr>) | |
| constexpr explicit(!is_convertible_v<_Gr, _Er>) | |
| expected(expected<_Up, _Gr>&& __x) | |
| noexcept(is_nothrow_constructible_v<_Er, _Gr>) | |
| : _M_void(), _M_has_value(__x._M_has_value) | |
| { | |
| if (!_M_has_value) | |
| std::construct_at(__builtin_addressof(_M_unex), | |
| std::move(__x)._M_unex); | |
| } | |
| template<typename _Gr = _Er> | |
| requires is_constructible_v<_Er, const _Gr&> | |
| constexpr explicit(!is_convertible_v<const _Gr&, _Er>) | |
| expected(const unexpected<_Gr>& __u) | |
| noexcept(is_nothrow_constructible_v<_Er, const _Gr&>) | |
| : _M_unex(__u.error()), _M_has_value(false) | |
| { } | |
| template<typename _Gr = _Er> | |
| requires is_constructible_v<_Er, _Gr> | |
| constexpr explicit(!is_convertible_v<_Gr, _Er>) | |
| expected(unexpected<_Gr>&& __u) | |
| noexcept(is_nothrow_constructible_v<_Er, _Gr>) | |
| : _M_unex(std::move(__u).error()), _M_has_value(false) | |
| { } | |
| constexpr explicit | |
| expected(in_place_t) noexcept | |
| : expected() | |
| { } | |
| template<typename... _Args> | |
| requires is_constructible_v<_Er, _Args...> | |
| constexpr explicit | |
| expected(unexpect_t, _Args&&... __args) | |
| noexcept(is_nothrow_constructible_v<_Er, _Args...>) | |
| : _M_unex(std::forward<_Args>(__args)...), _M_has_value(false) | |
| { } | |
| template<typename _Up, typename... _Args> | |
| requires is_constructible_v<_Er, initializer_list<_Up>&, _Args...> | |
| constexpr explicit | |
| expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) | |
| noexcept(is_nothrow_constructible_v<_Er, initializer_list<_Up>&, | |
| _Args...>) | |
| : _M_unex(__il, std::forward<_Args>(__args)...), _M_has_value(false) | |
| { } | |
| constexpr ~expected() = default; | |
| constexpr ~expected() requires (!is_trivially_destructible_v<_Er>) | |
| { | |
| if (!_M_has_value) | |
| std::destroy_at(__builtin_addressof(_M_unex)); | |
| } | |
| // assignment | |
| // Deleted copy assignment, when constraints not met for other overloads | |
| expected& operator=(const expected&) = delete; | |
| // Trivial copy assignment | |
| expected& | |
| operator=(const expected&) | |
| noexcept(__and_v<is_nothrow_copy_constructible<_Er>, | |
| is_nothrow_copy_assignable<_Er>>) | |
| requires __expected::__usable_for_trivial_assign<const _Er&> | |
| = default; | |
| // Non-trivial copy assignment | |
| constexpr expected& | |
| operator=(const expected& __x) | |
| noexcept(__and_v<is_nothrow_copy_constructible<_Er>, | |
| is_nothrow_copy_assignable<_Er>>) | |
| requires __expected::__usable_for_assign<const _Er&> | |
| { | |
| if (__x._M_has_value) | |
| emplace(); | |
| else | |
| _M_assign_unex(__x._M_unex); | |
| return *this; | |
| } | |
| // Trivial move assignment | |
| expected& | |
| operator=(expected&&) | |
| noexcept(__and_v<is_nothrow_move_constructible<_Er>, | |
| is_nothrow_move_assignable<_Er>>) | |
| requires __expected::__usable_for_trivial_assign<_Er&&> | |
| = default; | |
| // Non-trivial move assignment | |
| constexpr expected& | |
| operator=(expected&& __x) | |
| noexcept(__and_v<is_nothrow_move_constructible<_Er>, | |
| is_nothrow_move_assignable<_Er>>) | |
| requires __expected::__usable_for_assign<_Er&&> | |
| { | |
| if (__x._M_has_value) | |
| emplace(); | |
| else | |
| _M_assign_unex(std::move(__x._M_unex)); | |
| return *this; | |
| } | |
| template<typename _Gr> | |
| requires is_constructible_v<_Er, const _Gr&> | |
| && is_assignable_v<_Er&, const _Gr&> | |
| constexpr expected& | |
| operator=(const unexpected<_Gr>& __e) | |
| { | |
| _M_assign_unex(__e.error()); | |
| return *this; | |
| } | |
| template<typename _Gr> | |
| requires is_constructible_v<_Er, _Gr> | |
| && is_assignable_v<_Er&, _Gr> | |
| constexpr expected& | |
| operator=(unexpected<_Gr>&& __e) | |
| { | |
| _M_assign_unex(std::move(__e.error())); | |
| return *this; | |
| } | |
| // modifiers | |
| constexpr void | |
| emplace() noexcept | |
| { | |
| if (!_M_has_value) | |
| { | |
| std::destroy_at(__builtin_addressof(_M_unex)); | |
| _M_has_value = true; | |
| } | |
| } | |
| // swap | |
| constexpr void | |
| swap(expected& __x) | |
| noexcept(__and_v<is_nothrow_swappable<_Er&>, | |
| is_nothrow_move_constructible<_Er>>) | |
| requires is_swappable_v<_Er> && is_move_constructible_v<_Er> | |
| { | |
| if (_M_has_value) | |
| { | |
| if (!__x._M_has_value) | |
| { | |
| std::construct_at(__builtin_addressof(_M_unex), | |
| std::move(__x._M_unex)); // might throw | |
| std::destroy_at(__builtin_addressof(__x._M_unex)); | |
| _M_has_value = false; | |
| __x._M_has_value = true; | |
| } | |
| } | |
| else | |
| { | |
| if (__x._M_has_value) | |
| { | |
| std::construct_at(__builtin_addressof(__x._M_unex), | |
| std::move(_M_unex)); // might throw | |
| std::destroy_at(__builtin_addressof(_M_unex)); | |
| _M_has_value = true; | |
| __x._M_has_value = false; | |
| } | |
| else | |
| { | |
| using std::swap; | |
| swap(_M_unex, __x._M_unex); | |
| } | |
| } | |
| } | |
| // observers | |
| [[nodiscard]] | |
| constexpr explicit | |
| operator bool() const noexcept { return _M_has_value; } | |
| [[nodiscard]] | |
| constexpr bool has_value() const noexcept { return _M_has_value; } | |
| constexpr void | |
| operator*() const noexcept { __glibcxx_assert(_M_has_value); } | |
| constexpr void | |
| value() const& | |
| { | |
| static_assert( is_copy_constructible_v<_Er> ); | |
| if (_M_has_value) [[likely]] | |
| return; | |
| _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(_M_unex)); | |
| } | |
| constexpr void | |
| value() && | |
| { | |
| static_assert( is_copy_constructible_v<_Er> ); | |
| static_assert( is_move_constructible_v<_Er> ); | |
| if (_M_has_value) [[likely]] | |
| return; | |
| _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex))); | |
| } | |
| constexpr const _Er& | |
| error() const & noexcept | |
| { | |
| __glibcxx_assert(!_M_has_value); | |
| return _M_unex; | |
| } | |
| constexpr _Er& | |
| error() & noexcept | |
| { | |
| __glibcxx_assert(!_M_has_value); | |
| return _M_unex; | |
| } | |
| constexpr const _Er&& | |
| error() const && noexcept | |
| { | |
| __glibcxx_assert(!_M_has_value); | |
| return std::move(_M_unex); | |
| } | |
| constexpr _Er&& | |
| error() && noexcept | |
| { | |
| __glibcxx_assert(!_M_has_value); | |
| return std::move(_M_unex); | |
| } | |
| template<typename _Gr = _Er> | |
| constexpr _Er | |
| error_or(_Gr&& __e) const& | |
| { | |
| static_assert( is_copy_constructible_v<_Er> ); | |
| static_assert( is_convertible_v<_Gr, _Er> ); | |
| if (_M_has_value) | |
| return std::forward<_Gr>(__e); | |
| return _M_unex; | |
| } | |
| template<typename _Gr = _Er> | |
| constexpr _Er | |
| error_or(_Gr&& __e) && | |
| { | |
| static_assert( is_move_constructible_v<_Er> ); | |
| static_assert( is_convertible_v<_Gr, _Er> ); | |
| if (_M_has_value) | |
| return std::forward<_Gr>(__e); | |
| return std::move(_M_unex); | |
| } | |
| // monadic operations | |
| template<typename _Fn> requires is_constructible_v<_Er, _Er&> | |
| constexpr auto | |
| and_then(_Fn&& __f) & | |
| { | |
| using _Up = __expected::__result0<_Fn>; | |
| static_assert(__expected::__is_expected<_Up>); | |
| static_assert(is_same_v<typename _Up::error_type, _Er>); | |
| if (has_value()) | |
| return std::__invoke(std::forward<_Fn>(__f)); | |
| else | |
| return _Up(unexpect, _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, const _Er&> | |
| constexpr auto | |
| and_then(_Fn&& __f) const & | |
| { | |
| using _Up = __expected::__result0<_Fn>; | |
| static_assert(__expected::__is_expected<_Up>); | |
| static_assert(is_same_v<typename _Up::error_type, _Er>); | |
| if (has_value()) | |
| return std::__invoke(std::forward<_Fn>(__f)); | |
| else | |
| return _Up(unexpect, _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, _Er> | |
| constexpr auto | |
| and_then(_Fn&& __f) && | |
| { | |
| using _Up = __expected::__result0<_Fn>; | |
| static_assert(__expected::__is_expected<_Up>); | |
| static_assert(is_same_v<typename _Up::error_type, _Er>); | |
| if (has_value()) | |
| return std::__invoke(std::forward<_Fn>(__f)); | |
| else | |
| return _Up(unexpect, std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, const _Er> | |
| constexpr auto | |
| and_then(_Fn&& __f) const && | |
| { | |
| using _Up = __expected::__result0<_Fn>; | |
| static_assert(__expected::__is_expected<_Up>); | |
| static_assert(is_same_v<typename _Up::error_type, _Er>); | |
| if (has_value()) | |
| return std::__invoke(std::forward<_Fn>(__f)); | |
| else | |
| return _Up(unexpect, std::move(_M_unex)); | |
| } | |
| template<typename _Fn> | |
| constexpr auto | |
| or_else(_Fn&& __f) & | |
| { | |
| using _Gr = __expected::__result<_Fn, _Er&>; | |
| static_assert(__expected::__is_expected<_Gr>); | |
| static_assert(is_same_v<typename _Gr::value_type, _Tp>); | |
| if (has_value()) | |
| return _Gr(); | |
| else | |
| return std::__invoke(std::forward<_Fn>(__f), _M_unex); | |
| } | |
| template<typename _Fn> | |
| constexpr auto | |
| or_else(_Fn&& __f) const & | |
| { | |
| using _Gr = __expected::__result<_Fn, const _Er&>; | |
| static_assert(__expected::__is_expected<_Gr>); | |
| static_assert(is_same_v<typename _Gr::value_type, _Tp>); | |
| if (has_value()) | |
| return _Gr(); | |
| else | |
| return std::__invoke(std::forward<_Fn>(__f), _M_unex); | |
| } | |
| template<typename _Fn> | |
| constexpr auto | |
| or_else(_Fn&& __f) && | |
| { | |
| using _Gr = __expected::__result<_Fn, _Er&&>; | |
| static_assert(__expected::__is_expected<_Gr>); | |
| static_assert(is_same_v<typename _Gr::value_type, _Tp>); | |
| if (has_value()) | |
| return _Gr(); | |
| else | |
| return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex)); | |
| } | |
| template<typename _Fn> | |
| constexpr auto | |
| or_else(_Fn&& __f) const && | |
| { | |
| using _Gr = __expected::__result<_Fn, const _Er&&>; | |
| static_assert(__expected::__is_expected<_Gr>); | |
| static_assert(is_same_v<typename _Gr::value_type, _Tp>); | |
| if (has_value()) | |
| return _Gr(); | |
| else | |
| return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, _Er&> | |
| constexpr auto | |
| transform(_Fn&& __f) & | |
| { | |
| using _Up = __expected::__result0_xform<_Fn>; | |
| using _Res = expected<_Up, _Er>; | |
| if (has_value()) | |
| return _Res(__in_place_inv{}, std::forward<_Fn>(__f)); | |
| else | |
| return _Res(unexpect, _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, const _Er&> | |
| constexpr auto | |
| transform(_Fn&& __f) const & | |
| { | |
| using _Up = __expected::__result0_xform<_Fn>; | |
| using _Res = expected<_Up, _Er>; | |
| if (has_value()) | |
| return _Res(__in_place_inv{}, std::forward<_Fn>(__f)); | |
| else | |
| return _Res(unexpect, _M_unex); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, _Er> | |
| constexpr auto | |
| transform(_Fn&& __f) && | |
| { | |
| using _Up = __expected::__result0_xform<_Fn>; | |
| using _Res = expected<_Up, _Er>; | |
| if (has_value()) | |
| return _Res(__in_place_inv{}, std::forward<_Fn>(__f)); | |
| else | |
| return _Res(unexpect, std::move(_M_unex)); | |
| } | |
| template<typename _Fn> requires is_constructible_v<_Er, const _Er> | |
| constexpr auto | |
| transform(_Fn&& __f) const && | |
| { | |
| using _Up = __expected::__result0_xform<_Fn>; | |
| using _Res = expected<_Up, _Er>; | |
| if (has_value()) | |
| return _Res(__in_place_inv{}, std::forward<_Fn>(__f)); | |
| else | |
| return _Res(unexpect, std::move(_M_unex)); | |
| } | |
| template<typename _Fn> | |
| constexpr auto | |
| transform_error(_Fn&& __f) & | |
| { | |
| using _Gr = __expected::__result_xform<_Fn, _Er&>; | |
| using _Res = expected<_Tp, _Gr>; | |
| if (has_value()) | |
| return _Res(); | |
| else | |
| return _Res(__unexpect_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| _M_unex); | |
| }); | |
| } | |
| template<typename _Fn> | |
| constexpr auto | |
| transform_error(_Fn&& __f) const & | |
| { | |
| using _Gr = __expected::__result_xform<_Fn, const _Er&>; | |
| using _Res = expected<_Tp, _Gr>; | |
| if (has_value()) | |
| return _Res(); | |
| else | |
| return _Res(__unexpect_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| _M_unex); | |
| }); | |
| } | |
| template<typename _Fn> | |
| constexpr auto | |
| transform_error(_Fn&& __f) && | |
| { | |
| using _Gr = __expected::__result_xform<_Fn, _Er&&>; | |
| using _Res = expected<_Tp, _Gr>; | |
| if (has_value()) | |
| return _Res(); | |
| else | |
| return _Res(__unexpect_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| std::move(_M_unex)); | |
| }); | |
| } | |
| template<typename _Fn> | |
| constexpr auto | |
| transform_error(_Fn&& __f) const && | |
| { | |
| using _Gr = __expected::__result_xform<_Fn, const _Er&&>; | |
| using _Res = expected<_Tp, _Gr>; | |
| if (has_value()) | |
| return _Res(); | |
| else | |
| return _Res(__unexpect_inv{}, [&]() { | |
| return std::__invoke(std::forward<_Fn>(__f), | |
| std::move(_M_unex)); | |
| }); | |
| } | |
| // equality operators | |
| template<typename _Up, typename _Er2> | |
| requires is_void_v<_Up> | |
| && requires (const _Er& __e, const _Er2& __e2) { | |
| { __e == __e2 } -> convertible_to<bool>; | |
| } | |
| [[nodiscard]] | |
| friend constexpr bool | |
| operator==(const expected& __x, const expected<_Up, _Er2>& __y) | |
| noexcept(noexcept(bool(__x.error() == __y.error()))) | |
| { | |
| if (__x.has_value() != __y.has_value()) | |
| return false; | |
| if (__x.has_value()) | |
| return true; | |
| return __x.error() == __y.error(); | |
| } | |
| template<typename _Er2> | |
| requires requires (const _Er& __e, const _Er2& __e2) { | |
| { __e == __e2 } -> convertible_to<bool>; | |
| } | |
| [[nodiscard]] | |
| friend constexpr bool | |
| operator==(const expected& __x, const unexpected<_Er2>& __e) | |
| noexcept(noexcept(bool(__x.error() == __e.error()))) | |
| { | |
| if (!__x.has_value()) | |
| return __x.error() == __e.error(); | |
| return false; | |
| } | |
| friend constexpr void | |
| swap(expected& __x, expected& __y) | |
| noexcept(noexcept(__x.swap(__y))) | |
| requires requires { __x.swap(__y); } | |
| { __x.swap(__y); } | |
| private: | |
| template<typename, typename> friend class expected; | |
| template<typename _Vp> | |
| constexpr void | |
| _M_assign_unex(_Vp&& __v) | |
| { | |
| if (_M_has_value) | |
| { | |
| std::construct_at(__builtin_addressof(_M_unex), | |
| std::forward<_Vp>(__v)); | |
| _M_has_value = false; | |
| } | |
| else | |
| _M_unex = std::forward<_Vp>(__v); | |
| } | |
| using __in_place_inv = __expected::__in_place_inv; | |
| using __unexpect_inv = __expected::__unexpect_inv; | |
| template<typename _Fn> | |
| explicit constexpr | |
| expected(__in_place_inv, _Fn&& __fn) | |
| : _M_void(), _M_has_value(true) | |
| { std::forward<_Fn>(__fn)(); } | |
| template<typename _Fn> | |
| explicit constexpr | |
| expected(__unexpect_inv, _Fn&& __fn) | |
| : _M_unex(std::forward<_Fn>(__fn)()), _M_has_value(false) | |
| { } | |
| union { | |
| struct { } _M_void; | |
| _Er _M_unex; | |
| }; | |
| bool _M_has_value; | |
| }; | |
| /// @} | |
| _GLIBCXX_END_NAMESPACE_VERSION | |
| } // namespace std | |
| #endif // __cpp_lib_expected | |
| #endif // _GLIBCXX_EXPECTED |