зеркало из https://github.com/microsoft/STL.git
1925 строки
82 KiB
C++
1925 строки
82 KiB
C++
// expected standard header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef _EXPECTED_
|
|
#define _EXPECTED_
|
|
#include <yvals.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
#if !_HAS_CXX23
|
|
_EMIT_STL_WARNING(STL4038, "The contents of <expected> are available only with C++23 or later.");
|
|
#else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv
|
|
#include <exception>
|
|
#include <initializer_list>
|
|
#include <type_traits>
|
|
#include <xutility>
|
|
|
|
#pragma pack(push, _CRT_PACKING)
|
|
#pragma warning(push, _STL_WARNING_LEVEL)
|
|
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
|
_STL_DISABLE_CLANG_WARNINGS
|
|
#pragma push_macro("new")
|
|
#undef new
|
|
|
|
_STD_BEGIN
|
|
|
|
_EXPORT_STD template <class _Err>
|
|
class unexpected;
|
|
|
|
template <class _Err>
|
|
struct _Check_unexpected_argument : true_type {
|
|
static_assert(is_object_v<_Err>, "E must be an object type. (N4950 [expected.un.general]/2)");
|
|
static_assert(!is_array_v<_Err>, "E must not be an array type. (N4950 [expected.un.general]/2)");
|
|
static_assert(!is_const_v<_Err>, "E must not be const. (N4950 [expected.un.general]/2)");
|
|
static_assert(!is_volatile_v<_Err>, "E must not be volatile. (N4950 [expected.un.general]/2)");
|
|
static_assert(!_Is_specialization_v<_Err, unexpected>,
|
|
"E must not be a specialization of unexpected. (N4950 [expected.un.general]/2)");
|
|
};
|
|
|
|
// [expected.un.general]
|
|
_EXPORT_STD template <class _Err>
|
|
class unexpected {
|
|
static_assert(_Check_unexpected_argument<_Err>::value);
|
|
|
|
template <class _Ty, class _Err2>
|
|
friend class expected;
|
|
|
|
public:
|
|
// [expected.un.cons]
|
|
template <class _UError = _Err>
|
|
requires (!is_same_v<remove_cvref_t<_UError>, unexpected> && !is_same_v<remove_cvref_t<_UError>, in_place_t>
|
|
&& is_constructible_v<_Err, _UError>)
|
|
constexpr explicit unexpected(_UError&& _Unex) noexcept(is_nothrow_constructible_v<_Err, _UError>) // strengthened
|
|
: _Unexpected(_STD forward<_UError>(_Unex)) {}
|
|
|
|
template <class... _Args>
|
|
requires is_constructible_v<_Err, _Args...>
|
|
constexpr explicit unexpected(in_place_t, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
|
|
: _Unexpected(_STD forward<_Args>(_Vals)...) {}
|
|
|
|
template <class _Uty, class... _Args>
|
|
requires is_constructible_v<_Err, initializer_list<_Uty>&, _Args...>
|
|
constexpr explicit unexpected(in_place_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Uty>&, _Args...>) // strengthened
|
|
: _Unexpected(_Ilist, _STD forward<_Args>(_Vals)...) {}
|
|
|
|
// [expected.un.obs]
|
|
_NODISCARD constexpr const _Err& error() const& noexcept {
|
|
return _Unexpected;
|
|
}
|
|
_NODISCARD constexpr _Err& error() & noexcept {
|
|
return _Unexpected;
|
|
}
|
|
_NODISCARD constexpr const _Err&& error() const&& noexcept {
|
|
return _STD move(_Unexpected);
|
|
}
|
|
_NODISCARD constexpr _Err&& error() && noexcept {
|
|
return _STD move(_Unexpected);
|
|
}
|
|
|
|
// [expected.un.swap]
|
|
constexpr void swap(unexpected& _Other) noexcept(is_nothrow_swappable_v<_Err>) {
|
|
static_assert(is_swappable_v<_Err>, "E must be swappable");
|
|
using _STD swap;
|
|
swap(_Unexpected, _Other._Unexpected); // intentional ADL
|
|
}
|
|
|
|
friend constexpr void swap(unexpected& _Left, unexpected& _Right) noexcept(is_nothrow_swappable_v<_Err>)
|
|
requires is_swappable<_Err>::value // TRANSITION, /permissive needs ::value
|
|
{
|
|
_Left.swap(_Right);
|
|
}
|
|
|
|
// [expected.un.eq]
|
|
template <class _UErr>
|
|
_NODISCARD friend constexpr bool operator==(const unexpected& _Left, const unexpected<_UErr>& _Right)
|
|
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
|
return _Left._Unexpected == _Right.error();
|
|
}
|
|
|
|
private:
|
|
_Err _Unexpected;
|
|
};
|
|
|
|
template <class _Err>
|
|
unexpected(_Err) -> unexpected<_Err>;
|
|
|
|
_EXPORT_STD template <class _Err>
|
|
class bad_expected_access;
|
|
|
|
template <>
|
|
class bad_expected_access<void> : public exception {
|
|
public:
|
|
_NODISCARD const char* __CLR_OR_THIS_CALL what() const noexcept override {
|
|
return "Bad expected access";
|
|
}
|
|
|
|
protected:
|
|
bad_expected_access() = default;
|
|
bad_expected_access(const bad_expected_access&) = default;
|
|
bad_expected_access(bad_expected_access&&) = default;
|
|
bad_expected_access& operator=(const bad_expected_access&) = default;
|
|
bad_expected_access& operator=(bad_expected_access&&) = default;
|
|
|
|
#if !_HAS_EXCEPTIONS
|
|
void _Doraise() const override { // perform class-specific exception handling
|
|
_RAISE(*this);
|
|
}
|
|
#endif // !_HAS_EXCEPTIONS
|
|
};
|
|
|
|
_EXPORT_STD template <class _Err>
|
|
class bad_expected_access : public bad_expected_access<void> {
|
|
public:
|
|
explicit bad_expected_access(_Err _Unex) noexcept(is_nothrow_move_constructible_v<_Err>) // strengthened
|
|
: _Unexpected(_STD move(_Unex)) {}
|
|
|
|
_NODISCARD const _Err& error() const& noexcept {
|
|
return _Unexpected;
|
|
}
|
|
_NODISCARD _Err& error() & noexcept {
|
|
return _Unexpected;
|
|
}
|
|
_NODISCARD const _Err&& error() const&& noexcept {
|
|
return _STD move(_Unexpected);
|
|
}
|
|
_NODISCARD _Err&& error() && noexcept {
|
|
return _STD move(_Unexpected);
|
|
}
|
|
|
|
private:
|
|
_Err _Unexpected;
|
|
};
|
|
|
|
_EXPORT_STD struct unexpect_t {
|
|
explicit unexpect_t() = default;
|
|
};
|
|
|
|
_EXPORT_STD inline constexpr unexpect_t unexpect{};
|
|
|
|
struct _Construct_expected_from_invoke_result_tag {
|
|
explicit _Construct_expected_from_invoke_result_tag() = default;
|
|
};
|
|
|
|
template <class _Fn, class... _Tys>
|
|
concept _Is_invoke_constructible = requires(_Fn&& _Func, _Tys&&... _Vals) {
|
|
static_cast<remove_cvref_t<invoke_result_t<_Fn, _Tys...>>>(
|
|
_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Tys>(_Vals)...));
|
|
};
|
|
|
|
template <class _Ty>
|
|
struct _Check_expected_argument : true_type {
|
|
static_assert(!is_reference_v<_Ty>, "T must not be a reference type. (N4950 [expected.object.general]/2)");
|
|
static_assert(!is_function_v<_Ty>, "T must not be a function type. (N4950 [expected.object.general]/2)");
|
|
static_assert(!is_array_v<_Ty>, "T must not be an array type. (N4950 [expected.object.general]/2)");
|
|
static_assert(!is_same_v<remove_cv_t<_Ty>, in_place_t>,
|
|
"T must not be (possibly cv-qualified) in_place_t. (N4950 [expected.object.general]/2)");
|
|
static_assert(!is_same_v<remove_cv_t<_Ty>, unexpect_t>,
|
|
"T must not be (possibly cv-qualified) unexpect_t. (N4950 [expected.object.general]/2)");
|
|
static_assert(!_Is_specialization_v<remove_cv_t<_Ty>, unexpected>,
|
|
"T must not be a (possibly cv-qualified) specialization of unexpected. (N4950 [expected.object.general]/2)");
|
|
};
|
|
|
|
template <class _Ty, class _Err>
|
|
concept _Expected_binary_copy_assignable =
|
|
is_copy_assignable_v<_Ty> && is_copy_constructible_v<_Ty> //
|
|
&& is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err>
|
|
&& (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>);
|
|
|
|
template <class _Ty, class _Err>
|
|
concept _Expected_binary_move_assignable =
|
|
is_move_assignable_v<_Ty> && is_move_constructible_v<_Ty> //
|
|
&& is_move_assignable_v<_Err> && is_move_constructible_v<_Err>
|
|
&& (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>);
|
|
|
|
template <class _Type> // used with both _Ty and _Err
|
|
concept _Trivially_copy_constructible_assignable_destructible =
|
|
is_trivially_copy_constructible_v<_Type> && is_trivially_copy_assignable_v<_Type>
|
|
&& is_trivially_destructible_v<_Type>;
|
|
|
|
template <class _Type> // used with both _Ty and _Err
|
|
concept _Trivially_move_constructible_assignable_destructible =
|
|
is_trivially_move_constructible_v<_Type> && is_trivially_move_assignable_v<_Type>
|
|
&& is_trivially_destructible_v<_Type>;
|
|
|
|
_EXPORT_STD template <class _Ty, class _Err>
|
|
class expected {
|
|
private:
|
|
static_assert(_Check_expected_argument<_Ty>::value);
|
|
static_assert(_Check_unexpected_argument<_Err>::value);
|
|
|
|
template <class _UTy, class _UErr>
|
|
friend class expected;
|
|
|
|
template <class _Uty, class _UErr>
|
|
static constexpr bool _Allow_unwrapping = disjunction_v<is_same<remove_cv_t<_Ty>, bool>,
|
|
negation<disjunction<is_constructible<_Ty, expected<_Uty, _UErr>&>, //
|
|
is_constructible<_Ty, expected<_Uty, _UErr>>, //
|
|
is_constructible<_Ty, const expected<_Uty, _UErr>&>, //
|
|
is_constructible<_Ty, const expected<_Uty, _UErr>>, //
|
|
is_convertible<expected<_Uty, _UErr>&, _Ty>, //
|
|
is_convertible<expected<_Uty, _UErr>&&, _Ty>, //
|
|
is_convertible<const expected<_Uty, _UErr>&, _Ty>, //
|
|
is_convertible<const expected<_Uty, _UErr>&&, _Ty>>>>
|
|
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>&>
|
|
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>>
|
|
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>&>
|
|
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>>;
|
|
|
|
public:
|
|
using value_type = _Ty;
|
|
using error_type = _Err;
|
|
using unexpected_type = unexpected<_Err>;
|
|
|
|
template <class _Uty>
|
|
using rebind = expected<_Uty, error_type>;
|
|
|
|
// [expected.object.cons]
|
|
constexpr expected() noexcept(is_nothrow_default_constructible_v<_Ty>) // strengthened
|
|
requires is_default_constructible_v<_Ty>
|
|
: _Value(), _Has_value(true) {}
|
|
|
|
constexpr expected(const expected& _Other)
|
|
noexcept(is_nothrow_copy_constructible_v<_Ty> && is_nothrow_copy_constructible_v<_Err>) // strengthened
|
|
requires (!(is_trivially_copy_constructible_v<_Ty> && is_trivially_copy_constructible_v<_Err>)
|
|
&& is_copy_constructible_v<_Ty> && is_copy_constructible_v<_Err>)
|
|
: _Has_value(_Other._Has_value) {
|
|
if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Value), _Other._Value);
|
|
} else {
|
|
_STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
|
|
}
|
|
}
|
|
|
|
expected(const expected&)
|
|
requires is_trivially_copy_constructible_v<_Ty> && is_trivially_copy_constructible_v<_Err>
|
|
= default;
|
|
|
|
expected(const expected&) = delete;
|
|
|
|
constexpr expected(expected&& _Other)
|
|
noexcept(is_nothrow_move_constructible_v<_Ty> && is_nothrow_move_constructible_v<_Err>)
|
|
requires (!(is_trivially_move_constructible_v<_Ty> && is_trivially_move_constructible_v<_Err>)
|
|
&& is_move_constructible_v<_Ty> && is_move_constructible_v<_Err>)
|
|
: _Has_value(_Other._Has_value) {
|
|
if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Value), _STD move(_Other._Value));
|
|
} else {
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
|
|
}
|
|
}
|
|
|
|
expected(expected&&)
|
|
requires is_trivially_move_constructible_v<_Ty> && is_trivially_move_constructible_v<_Err>
|
|
= default;
|
|
|
|
template <class _Uty, class _UErr>
|
|
requires _Different_from<expected<_Uty, _UErr>, expected> && is_constructible_v<_Ty, const _Uty&>
|
|
&& is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr>
|
|
constexpr explicit(!is_convertible_v<const _Uty&, _Ty> || !is_convertible_v<const _UErr&, _Err>)
|
|
expected(const expected<_Uty, _UErr>& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Ty, const _Uty&>
|
|
&& is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
|
|
: _Has_value(_Other._Has_value) {
|
|
if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Value), _Other._Value);
|
|
} else {
|
|
_STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
|
|
}
|
|
}
|
|
|
|
template <class _Uty, class _UErr>
|
|
requires _Different_from<expected<_Uty, _UErr>, expected> && is_constructible_v<_Ty, _Uty>
|
|
&& is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr>
|
|
constexpr explicit(!is_convertible_v<_Uty, _Ty> || !is_convertible_v<_UErr, _Err>)
|
|
expected(expected<_Uty, _UErr>&& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Ty, _Uty> && is_nothrow_constructible_v<_Err, _UErr>) // strengthened
|
|
: _Has_value(_Other._Has_value) {
|
|
if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Value), _STD move(_Other._Value));
|
|
} else {
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
|
|
}
|
|
}
|
|
|
|
template <class _Uty = _Ty>
|
|
requires (!is_same_v<remove_cvref_t<_Uty>, in_place_t> && !is_same_v<remove_cvref_t<_Uty>, expected>
|
|
&& !_Is_specialization_v<remove_cvref_t<_Uty>, unexpected>
|
|
&& (!is_same_v<remove_cv_t<_Ty>, bool>
|
|
#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10655311
|
|
|| !_Is_specialization_v<remove_cvref_t<_Uty>, expected>
|
|
#else // ^^^ no workaround / workaround vvv
|
|
|| !_Is_specialization_v<remove_cvref_t<_Uty>, _STD expected>
|
|
#endif // ^^^ workaround ^^^
|
|
)
|
|
&& is_constructible_v<_Ty, _Uty>)
|
|
constexpr explicit(!is_convertible_v<_Uty, _Ty>) expected(_Uty&& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Ty, _Uty>) // strengthened
|
|
: _Value(_STD forward<_Uty>(_Other)), _Has_value(true) {
|
|
}
|
|
|
|
template <class _UErr>
|
|
requires is_constructible_v<_Err, const _UErr&>
|
|
constexpr explicit(!is_convertible_v<const _UErr&, _Err>) expected(const unexpected<_UErr>& _Other) //
|
|
noexcept(is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
|
|
: _Unexpected(_Other._Unexpected), _Has_value(false) {}
|
|
|
|
template <class _UErr>
|
|
requires is_constructible_v<_Err, _UErr>
|
|
constexpr explicit(!is_convertible_v<_UErr, _Err>) expected(unexpected<_UErr>&& _Other) //
|
|
noexcept(is_nothrow_constructible_v<_Err, _UErr>) // strengthened
|
|
: _Unexpected(_STD move(_Other._Unexpected)), _Has_value(false) {}
|
|
|
|
template <class... _Args>
|
|
requires is_constructible_v<_Ty, _Args...>
|
|
constexpr explicit expected(in_place_t, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_Ty, _Args...>) // strengthened
|
|
: _Value(_STD forward<_Args>(_Vals)...), _Has_value(true) {}
|
|
|
|
template <class _Uty, class... _Args>
|
|
requires is_constructible_v<_Ty, initializer_list<_Uty>&, _Args...>
|
|
constexpr explicit expected(in_place_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_Ty, initializer_list<_Uty>&, _Args...>) // strengthened
|
|
: _Value(_Ilist, _STD forward<_Args>(_Vals)...), _Has_value(true) {}
|
|
|
|
template <class... _Args>
|
|
requires is_constructible_v<_Err, _Args...>
|
|
constexpr explicit expected(unexpect_t, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
|
|
: _Unexpected(_STD forward<_Args>(_Vals)...), _Has_value(false) {}
|
|
|
|
template <class _Uty, class... _Args>
|
|
requires is_constructible_v<_Err, initializer_list<_Uty>&, _Args...>
|
|
constexpr explicit expected(unexpect_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Uty>&, _Args...>) // strengthened
|
|
: _Unexpected(_Ilist, _STD forward<_Args>(_Vals)...), _Has_value(false) {}
|
|
|
|
// [expected.object.dtor]
|
|
constexpr ~expected()
|
|
#ifndef __clang__ // TRANSITION, LLVM-59854
|
|
noexcept
|
|
#endif // ^^^ no workaround ^^^
|
|
{
|
|
if (_Has_value) {
|
|
if constexpr (!is_trivially_destructible_v<_Ty>) {
|
|
_Value.~_Ty();
|
|
}
|
|
} else {
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Unexpected.~_Err();
|
|
}
|
|
}
|
|
}
|
|
|
|
~expected()
|
|
requires is_trivially_destructible_v<_Ty> && is_trivially_destructible_v<_Err>
|
|
= default;
|
|
|
|
// [expected.object.assign]
|
|
template <class _Uty>
|
|
requires is_nothrow_move_constructible_v<_Uty>
|
|
struct _NODISCARD _GuardTy {
|
|
constexpr _GuardTy(_Uty* _Target_, _Uty* _Tmp_) noexcept : _Target(_Target_), _Tmp(_Tmp_) {}
|
|
constexpr ~_GuardTy() noexcept {
|
|
if (_Target) {
|
|
_STD construct_at(_Target, _STD move(*_Tmp));
|
|
}
|
|
}
|
|
_Uty* _Target;
|
|
_Uty* _Tmp;
|
|
};
|
|
|
|
template <class _First, class _Second, class... _Args>
|
|
static constexpr void _Reinit_expected(_First& _New_val, _Second& _Old_val, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_First, _Args...>) /* strengthened */ {
|
|
if constexpr (is_nothrow_constructible_v<_First, _Args...>) {
|
|
if constexpr (!is_trivially_destructible_v<_Second>) {
|
|
_Old_val.~_Second();
|
|
}
|
|
_STD construct_at(_STD addressof(_New_val), _STD forward<_Args>(_Vals)...);
|
|
} else if constexpr (is_nothrow_move_constructible_v<_First>) {
|
|
_First _Tmp(_STD forward<_Args>(_Vals)...);
|
|
if constexpr (!is_trivially_destructible_v<_Second>) {
|
|
_Old_val.~_Second();
|
|
}
|
|
_STD construct_at(_STD addressof(_New_val), _STD move(_Tmp));
|
|
} else {
|
|
_Second _Tmp(_STD move(_Old_val));
|
|
if constexpr (!is_trivially_destructible_v<_Second>) {
|
|
_Old_val.~_Second();
|
|
}
|
|
|
|
_GuardTy<_Second> _Guard{_STD addressof(_Old_val), _STD addressof(_Tmp)};
|
|
_STD construct_at(_STD addressof(_New_val), _STD forward<_Args>(_Vals)...);
|
|
_Guard._Target = nullptr;
|
|
}
|
|
}
|
|
|
|
constexpr expected& operator=(const expected& _Other)
|
|
noexcept(is_nothrow_copy_constructible_v<_Ty> && is_nothrow_copy_constructible_v<_Err>
|
|
&& is_nothrow_copy_assignable_v<_Ty> && is_nothrow_copy_assignable_v<_Err>) // strengthened
|
|
requires _Expected_binary_copy_assignable<_Ty, _Err>
|
|
{
|
|
if (_Has_value && _Other._Has_value) {
|
|
_Value = _Other._Value;
|
|
} else if (_Has_value) {
|
|
_Reinit_expected(_Unexpected, _Value, _Other._Unexpected);
|
|
} else if (_Other._Has_value) {
|
|
_Reinit_expected(_Value, _Unexpected, _Other._Value);
|
|
} else {
|
|
_Unexpected = _Other._Unexpected;
|
|
}
|
|
|
|
_Has_value = _Other._Has_value;
|
|
return *this;
|
|
}
|
|
|
|
expected& operator=(const expected&)
|
|
requires _Expected_binary_copy_assignable<_Ty, _Err>
|
|
&& _Trivially_copy_constructible_assignable_destructible<_Ty>
|
|
&& _Trivially_copy_constructible_assignable_destructible<_Err>
|
|
= default;
|
|
|
|
expected& operator=(const expected&) = delete;
|
|
|
|
constexpr expected& operator=(expected&& _Other)
|
|
noexcept(is_nothrow_move_constructible_v<_Ty> && is_nothrow_move_constructible_v<_Err>
|
|
&& is_nothrow_move_assignable_v<_Ty> && is_nothrow_move_assignable_v<_Err>)
|
|
requires _Expected_binary_move_assignable<_Ty, _Err>
|
|
{
|
|
if (_Has_value && _Other._Has_value) {
|
|
_Value = _STD move(_Other._Value);
|
|
} else if (_Has_value) {
|
|
_Reinit_expected(_Unexpected, _Value, _STD move(_Other._Unexpected));
|
|
} else if (_Other._Has_value) {
|
|
_Reinit_expected(_Value, _Unexpected, _STD move(_Other._Value));
|
|
} else {
|
|
_Unexpected = _STD move(_Other._Unexpected);
|
|
}
|
|
|
|
_Has_value = _Other._Has_value;
|
|
return *this;
|
|
}
|
|
|
|
expected& operator=(expected&&)
|
|
requires _Expected_binary_move_assignable<_Ty, _Err>
|
|
&& _Trivially_move_constructible_assignable_destructible<_Ty>
|
|
&& _Trivially_move_constructible_assignable_destructible<_Err>
|
|
= default;
|
|
|
|
template <class _Uty = _Ty>
|
|
requires (!is_same_v<remove_cvref_t<_Uty>, expected> && !_Is_specialization_v<remove_cvref_t<_Uty>, unexpected>
|
|
&& is_constructible_v<_Ty, _Uty> && is_assignable_v<_Ty&, _Uty>
|
|
&& (is_nothrow_constructible_v<_Ty, _Uty> || is_nothrow_move_constructible_v<_Ty>
|
|
|| is_nothrow_move_constructible_v<_Err>) )
|
|
constexpr expected& operator=(_Uty&& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Ty, _Uty> && is_nothrow_assignable_v<_Ty&, _Uty>) /* strengthened */ {
|
|
if (_Has_value) {
|
|
_Value = _STD forward<_Uty>(_Other);
|
|
} else {
|
|
_Reinit_expected(_Value, _Unexpected, _STD forward<_Uty>(_Other));
|
|
_Has_value = true;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <class _UErr>
|
|
requires (is_constructible_v<_Err, const _UErr&> && is_assignable_v<_Err&, const _UErr&>
|
|
&& (is_nothrow_constructible_v<_Err, const _UErr&> || is_nothrow_move_constructible_v<_Ty>
|
|
|| is_nothrow_move_constructible_v<_Err>) )
|
|
constexpr expected& operator=(const unexpected<_UErr>& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Err, const _UErr&>
|
|
&& is_nothrow_assignable_v<_Err&, const _UErr&>) /* strengthened */ {
|
|
if (_Has_value) {
|
|
_Reinit_expected(_Unexpected, _Value, _Other._Unexpected);
|
|
_Has_value = false;
|
|
} else {
|
|
_Unexpected = _Other._Unexpected;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <class _UErr>
|
|
requires (is_constructible_v<_Err, _UErr> && is_assignable_v<_Err&, _UErr>
|
|
&& (is_nothrow_constructible_v<_Err, _UErr> || is_nothrow_move_constructible_v<_Ty>
|
|
|| is_nothrow_move_constructible_v<_Err>) )
|
|
constexpr expected& operator=(unexpected<_UErr>&& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Err, _UErr> && is_nothrow_assignable_v<_Err&, _UErr>) /* strengthened */ {
|
|
if (_Has_value) {
|
|
_Reinit_expected(_Unexpected, _Value, _STD move(_Other._Unexpected));
|
|
_Has_value = false;
|
|
} else {
|
|
_Unexpected = _STD move(_Other._Unexpected);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <class... _Args>
|
|
requires is_nothrow_constructible_v<_Ty, _Args...>
|
|
constexpr _Ty& emplace(_Args&&... _Vals) noexcept {
|
|
if (_Has_value) {
|
|
if constexpr (!is_trivially_destructible_v<_Ty>) {
|
|
_Value.~_Ty();
|
|
}
|
|
} else {
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Unexpected.~_Err();
|
|
}
|
|
_Has_value = true;
|
|
}
|
|
|
|
return *_STD construct_at(_STD addressof(_Value), _STD forward<_Args>(_Vals)...);
|
|
}
|
|
|
|
template <class _Uty, class... _Args>
|
|
requires is_nothrow_constructible_v<_Ty, initializer_list<_Uty>&, _Args...>
|
|
constexpr _Ty& emplace(initializer_list<_Uty> _Ilist, _Args&&... _Vals) noexcept {
|
|
if (_Has_value) {
|
|
if constexpr (!is_trivially_destructible_v<_Ty>) {
|
|
_Value.~_Ty();
|
|
}
|
|
} else {
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Unexpected.~_Err();
|
|
}
|
|
_Has_value = true;
|
|
}
|
|
|
|
return *_STD construct_at(_STD addressof(_Value), _Ilist, _STD forward<_Args>(_Vals)...);
|
|
}
|
|
|
|
// [expected.object.swap]
|
|
constexpr void swap(expected& _Other)
|
|
noexcept(is_nothrow_move_constructible_v<_Ty> && is_nothrow_swappable_v<_Ty>
|
|
&& is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)
|
|
requires is_swappable_v<_Ty> && is_swappable_v<_Err> //
|
|
&& is_move_constructible_v<_Ty> && is_move_constructible_v<_Err>
|
|
&& (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>)
|
|
{
|
|
using _STD swap;
|
|
if (_Has_value && _Other._Has_value) {
|
|
swap(_Value, _Other._Value); // intentional ADL
|
|
} else if (_Has_value) {
|
|
if constexpr (is_nothrow_move_constructible_v<_Err>) {
|
|
_Err _Tmp(_STD move(_Other._Unexpected));
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Other._Unexpected.~_Err();
|
|
}
|
|
|
|
if constexpr (is_nothrow_move_constructible_v<_Ty>) {
|
|
_STD construct_at(_STD addressof(_Other._Value), _STD move(_Value));
|
|
} else {
|
|
_GuardTy<_Err> _Guard{_STD addressof(_Other._Unexpected), _STD addressof(_Tmp)};
|
|
_STD construct_at(_STD addressof(_Other._Value), _STD move(_Value));
|
|
_Guard._Target = nullptr;
|
|
}
|
|
|
|
if constexpr (!is_trivially_destructible_v<_Ty>) {
|
|
_Value.~_Ty();
|
|
}
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Tmp));
|
|
} else {
|
|
_Ty _Tmp(_STD move(_Value));
|
|
if constexpr (!is_trivially_destructible_v<_Ty>) {
|
|
_Value.~_Ty();
|
|
}
|
|
|
|
_GuardTy<_Ty> _Guard{_STD addressof(_Value), _STD addressof(_Tmp)};
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
|
|
_Guard._Target = nullptr;
|
|
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Other._Unexpected.~_Err();
|
|
}
|
|
_STD construct_at(_STD addressof(_Other._Value), _STD move(_Tmp));
|
|
}
|
|
|
|
_Has_value = false;
|
|
_Other._Has_value = true;
|
|
} else if (_Other._Has_value) {
|
|
_Other.swap(*this);
|
|
} else {
|
|
swap(_Unexpected, _Other._Unexpected); // intentional ADL
|
|
}
|
|
}
|
|
|
|
friend constexpr void swap(expected& _Lhs, expected& _Rhs)
|
|
noexcept(is_nothrow_move_constructible_v<_Ty> && is_nothrow_swappable_v<_Ty>
|
|
&& is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)
|
|
requires is_swappable<_Ty>::value && is_swappable<_Err>::value // TRANSITION, /permissive needs ::value
|
|
&& is_move_constructible_v<_Ty> && is_move_constructible_v<_Err>
|
|
&& (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>)
|
|
{
|
|
_Lhs.swap(_Rhs);
|
|
}
|
|
|
|
// [expected.object.obs]
|
|
_NODISCARD constexpr const _Ty* operator->() const noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(_Has_value, "expected stores an error, not a value");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _STD addressof(_Value);
|
|
}
|
|
_NODISCARD constexpr _Ty* operator->() noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(_Has_value, "expected stores an error, not a value");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _STD addressof(_Value);
|
|
}
|
|
|
|
_NODISCARD constexpr const _Ty& operator*() const& noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(_Has_value, "expected stores an error, not a value");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _Value;
|
|
}
|
|
_NODISCARD constexpr _Ty& operator*() & noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(_Has_value, "expected stores an error, not a value");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _Value;
|
|
}
|
|
_NODISCARD constexpr const _Ty&& operator*() const&& noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(_Has_value, "expected stores an error, not a value");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _STD move(_Value);
|
|
}
|
|
_NODISCARD constexpr _Ty&& operator*() && noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(_Has_value, "expected stores an error, not a value");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _STD move(_Value);
|
|
}
|
|
|
|
_NODISCARD constexpr explicit operator bool() const noexcept {
|
|
return _Has_value;
|
|
}
|
|
_NODISCARD constexpr bool has_value() const noexcept {
|
|
return _Has_value;
|
|
}
|
|
|
|
_NODISCARD constexpr const _Ty& value() const& {
|
|
if (_Has_value) {
|
|
return _Value;
|
|
}
|
|
|
|
_Throw_bad_expected_access_lv();
|
|
}
|
|
_NODISCARD constexpr _Ty& value() & {
|
|
if (_Has_value) {
|
|
return _Value;
|
|
}
|
|
|
|
_Throw_bad_expected_access_lv();
|
|
}
|
|
_NODISCARD constexpr const _Ty&& value() const&& {
|
|
// TRANSITION, DevCom-1638273 and LLVM-53224
|
|
static_assert(
|
|
is_copy_constructible_v<_Err>, "is_copy_constructible_v<E> must be true. N4950 [expected.object.obs]/11");
|
|
static_assert(is_constructible_v<_Err, const _Err&&>,
|
|
"is_constructible_v<E, const E&&> must be true. N4950 [expected.object.obs]/11");
|
|
|
|
if (_Has_value) {
|
|
return _STD move(_Value);
|
|
}
|
|
|
|
_Throw_bad_expected_access_rv();
|
|
}
|
|
_NODISCARD constexpr _Ty&& value() && {
|
|
// TRANSITION, DevCom-1638273 and LLVM-53224
|
|
static_assert(
|
|
is_copy_constructible_v<_Err>, "is_copy_constructible_v<E> must be true. N4950 [expected.object.obs]/11");
|
|
static_assert(
|
|
is_move_constructible_v<_Err>, "is_constructible_v<E, E&&> must be true. N4950 [expected.object.obs]/11");
|
|
|
|
if (_Has_value) {
|
|
return _STD move(_Value);
|
|
}
|
|
|
|
_Throw_bad_expected_access_rv();
|
|
}
|
|
|
|
_NODISCARD constexpr const _Err& error() const& noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(!_Has_value, "expected stores a value, not an error");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _Unexpected;
|
|
}
|
|
_NODISCARD constexpr _Err& error() & noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(!_Has_value, "expected stores a value, not an error");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _Unexpected;
|
|
}
|
|
_NODISCARD constexpr const _Err&& error() const&& noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(!_Has_value, "expected stores a value, not an error");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _STD move(_Unexpected);
|
|
}
|
|
_NODISCARD constexpr _Err&& error() && noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(!_Has_value, "expected stores a value, not an error");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _STD move(_Unexpected);
|
|
}
|
|
|
|
template <class _Uty>
|
|
_NODISCARD constexpr _Ty value_or(_Uty&& _Other) const& noexcept(
|
|
is_nothrow_copy_constructible_v<_Ty> && is_nothrow_convertible_v<_Uty, _Ty>) /* strengthened */ {
|
|
static_assert(
|
|
is_copy_constructible_v<_Ty>, "is_copy_constructible_v<T> must be true. (N4950 [expected.object.obs]/18)");
|
|
static_assert(
|
|
is_convertible_v<_Uty, _Ty>, "is_convertible_v<U, T> must be true. (N4950 [expected.object.obs]/18)");
|
|
|
|
if (_Has_value) {
|
|
return _Value;
|
|
} else {
|
|
return static_cast<_Ty>(_STD forward<_Uty>(_Other));
|
|
}
|
|
}
|
|
template <class _Uty>
|
|
_NODISCARD constexpr _Ty value_or(_Uty&& _Other) && noexcept(
|
|
is_nothrow_move_constructible_v<_Ty> && is_nothrow_convertible_v<_Uty, _Ty>) /* strengthened */ {
|
|
static_assert(
|
|
is_move_constructible_v<_Ty>, "is_move_constructible_v<T> must be true. (N4950 [expected.object.obs]/20)");
|
|
static_assert(
|
|
is_convertible_v<_Uty, _Ty>, "is_convertible_v<U, T> must be true. (N4950 [expected.object.obs]/20)");
|
|
|
|
if (_Has_value) {
|
|
return _STD move(_Value);
|
|
} else {
|
|
return static_cast<_Ty>(_STD forward<_Uty>(_Other));
|
|
}
|
|
}
|
|
|
|
template <class _Uty = _Err>
|
|
_NODISCARD constexpr _Err error_or(_Uty&& _Other) const& noexcept(
|
|
is_nothrow_copy_constructible_v<_Err> && is_nothrow_convertible_v<_Uty, _Err>) /* strengthened */ {
|
|
static_assert(
|
|
is_copy_constructible_v<_Err>, "is_copy_constructible_v<E> must be true. (N4950 [expected.object.obs]/22)");
|
|
static_assert(
|
|
is_convertible_v<_Uty, _Err>, "is_convertible_v<G, E> must be true. (N4950 [expected.object.obs]/22)");
|
|
|
|
if (_Has_value) {
|
|
return _STD forward<_Uty>(_Other);
|
|
} else {
|
|
return _Unexpected;
|
|
}
|
|
}
|
|
|
|
template <class _Uty = _Err>
|
|
_NODISCARD constexpr _Err error_or(_Uty&& _Other) && noexcept(
|
|
is_nothrow_move_constructible_v<_Err> && is_nothrow_convertible_v<_Uty, _Err>) /* strengthened */ {
|
|
static_assert(
|
|
is_move_constructible_v<_Err>, "is_move_constructible_v<E> must be true. (N4950 [expected.object.obs]/24)");
|
|
static_assert(
|
|
is_convertible_v<_Uty, _Err>, "is_convertible_v<G, E> must be true. (N4950 [expected.object.obs]/24)");
|
|
|
|
if (_Has_value) {
|
|
return _STD forward<_Uty>(_Other);
|
|
} else {
|
|
return _STD move(_Unexpected);
|
|
}
|
|
}
|
|
|
|
// [expected.object.monadic]
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Err, _Err&>
|
|
constexpr auto and_then(_Fn&& _Func) & {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, _Ty&>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<T, E>::and_then(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.object.monadic]/3)");
|
|
static_assert(is_same_v<typename _Uty::error_type, _Err>,
|
|
"expected<T, E>::and_then(F) requires the error type of the return type of F to be E. "
|
|
"(N4950 [expected.object.monadic]/3)");
|
|
|
|
if (_Has_value) {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _Value);
|
|
} else {
|
|
return _Uty{unexpect, _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_copy_constructible_v<_Err>
|
|
constexpr auto and_then(_Fn&& _Func) const& {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, const _Ty&>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<T, E>::and_then(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.object.monadic]/3)");
|
|
static_assert(is_same_v<typename _Uty::error_type, _Err>,
|
|
"expected<T, E>::and_then(F) requires the error type of the return type of F to be E. "
|
|
"(N4950 [expected.object.monadic]/3)");
|
|
|
|
if (_Has_value) {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _Value);
|
|
} else {
|
|
return _Uty{unexpect, _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_move_constructible_v<_Err>
|
|
constexpr auto and_then(_Fn&& _Func) && {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, _Ty>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<T, E>::and_then(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.object.monadic]/7)");
|
|
static_assert(is_same_v<typename _Uty::error_type, _Err>,
|
|
"expected<T, E>::and_then(F) requires the error type of the return type of F to be E. "
|
|
"(N4950 [expected.object.monadic]/7)");
|
|
|
|
if (_Has_value) {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value));
|
|
} else {
|
|
return _Uty{unexpect, _STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Err, const _Err>
|
|
constexpr auto and_then(_Fn&& _Func) const&& {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, const _Ty>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<T, E>::and_then(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.object.monadic]/7)");
|
|
static_assert(is_same_v<typename _Uty::error_type, _Err>,
|
|
"expected<T, E>::and_then(F) requires the error type of the return type of F to be E. "
|
|
"(N4950 [expected.object.monadic]/7)");
|
|
|
|
if (_Has_value) {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value));
|
|
} else {
|
|
return _Uty{unexpect, _STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Ty, _Ty&>
|
|
constexpr auto or_else(_Fn&& _Func) & {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, _Err&>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<T, E>::or_else(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.object.monadic]/11)");
|
|
static_assert(is_same_v<typename _Uty::value_type, _Ty>,
|
|
"expected<T, E>::or_else(F) requires the value type of the return type of F to be T. "
|
|
"(N4950 [expected.object.monadic]/11)");
|
|
|
|
if (_Has_value) {
|
|
return _Uty{in_place, _Value};
|
|
} else {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _Unexpected);
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_copy_constructible_v<_Ty>
|
|
constexpr auto or_else(_Fn&& _Func) const& {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, const _Err&>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<T, E>::or_else(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.object.monadic]/11)");
|
|
static_assert(is_same_v<typename _Uty::value_type, _Ty>,
|
|
"expected<T, E>::or_else(F) requires the value type of the return type of F to be T. "
|
|
"(N4950 [expected.object.monadic]/11)");
|
|
|
|
if (_Has_value) {
|
|
return _Uty{in_place, _Value};
|
|
} else {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _Unexpected);
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_move_constructible_v<_Ty>
|
|
constexpr auto or_else(_Fn&& _Func) && {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, _Err>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<T, E>::or_else(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.object.monadic]/15)");
|
|
static_assert(is_same_v<typename _Uty::value_type, _Ty>,
|
|
"expected<T, E>::or_else(F) requires the value type of the return type of F to be T. "
|
|
"(N4950 [expected.object.monadic]/15)");
|
|
|
|
if (_Has_value) {
|
|
return _Uty{in_place, _STD move(_Value)};
|
|
} else {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Unexpected));
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Ty, const _Ty>
|
|
constexpr auto or_else(_Fn&& _Func) const&& {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, const _Err>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<T, E>::or_else(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.object.monadic]/15)");
|
|
static_assert(is_same_v<typename _Uty::value_type, _Ty>,
|
|
"expected<T, E>::or_else(F) requires the value type of the return type of F to be T. "
|
|
"(N4950 [expected.object.monadic]/15)");
|
|
|
|
if (_Has_value) {
|
|
return _Uty{in_place, _STD move(_Value)};
|
|
} else {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Unexpected));
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Err, _Err&>
|
|
constexpr auto transform(_Fn&& _Func) & {
|
|
static_assert(invocable<_Fn, _Ty&>, "expected<T, E>::transform(F) requires that F is invocable with T. "
|
|
"(N4950 [expected.object.monadic]/19)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, _Ty&>>;
|
|
|
|
if constexpr (!is_void_v<_Uty>) {
|
|
static_assert(_Is_invoke_constructible<_Fn, _Ty&>,
|
|
"expected<T, E>::transform(F) requires that the return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.object.monadic]/19)");
|
|
}
|
|
static_assert(_Check_expected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
if constexpr (is_void_v<_Uty>) {
|
|
_STD invoke(_STD forward<_Fn>(_Func), _Value);
|
|
return expected<_Uty, _Err>{};
|
|
} else {
|
|
return expected<_Uty, _Err>{
|
|
_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _Value};
|
|
}
|
|
} else {
|
|
return expected<_Uty, _Err>{unexpect, _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_copy_constructible_v<_Err>
|
|
constexpr auto transform(_Fn&& _Func) const& {
|
|
static_assert(invocable<_Fn, const _Ty&>, "expected<T, E>::transform(F) requires that F is invocable with T. "
|
|
"(N4950 [expected.object.monadic]/19)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, const _Ty&>>;
|
|
|
|
if constexpr (!is_void_v<_Uty>) {
|
|
static_assert(_Is_invoke_constructible<_Fn, const _Ty&>,
|
|
"expected<T, E>::transform(F) requires that the return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.object.monadic]/19)");
|
|
}
|
|
static_assert(_Check_expected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
if constexpr (is_void_v<_Uty>) {
|
|
_STD invoke(_STD forward<_Fn>(_Func), _Value);
|
|
return expected<_Uty, _Err>{};
|
|
} else {
|
|
return expected<_Uty, _Err>{
|
|
_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _Value};
|
|
}
|
|
} else {
|
|
return expected<_Uty, _Err>{unexpect, _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_move_constructible_v<_Err>
|
|
constexpr auto transform(_Fn&& _Func) && {
|
|
static_assert(invocable<_Fn, _Ty>, "expected<T, E>::transform(F) requires that F is invocable with T. "
|
|
"(N4950 [expected.object.monadic]/23)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, _Ty>>;
|
|
|
|
if constexpr (!is_void_v<_Uty>) {
|
|
static_assert(_Is_invoke_constructible<_Fn, _Ty>,
|
|
"expected<T, E>::transform(F) requires that the return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.object.monadic]/23)");
|
|
}
|
|
static_assert(_Check_expected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
if constexpr (is_void_v<_Uty>) {
|
|
_STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value));
|
|
return expected<_Uty, _Err>{};
|
|
} else {
|
|
return expected<_Uty, _Err>{
|
|
_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(_Value)};
|
|
}
|
|
} else {
|
|
return expected<_Uty, _Err>{unexpect, _STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Err, const _Err>
|
|
constexpr auto transform(_Fn&& _Func) const&& {
|
|
static_assert(invocable<_Fn, const _Ty>, "expected<T, E>::transform(F) requires that F is invocable with T. "
|
|
"(N4950 [expected.object.monadic]/23)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, const _Ty>>;
|
|
|
|
if constexpr (!is_void_v<_Uty>) {
|
|
static_assert(_Is_invoke_constructible<_Fn, const _Ty>,
|
|
"expected<T, E>::transform(F) requires that the return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.object.monadic]/23)");
|
|
}
|
|
static_assert(_Check_expected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
if constexpr (is_void_v<_Uty>) {
|
|
_STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value));
|
|
return expected<_Uty, _Err>{};
|
|
} else {
|
|
return expected<_Uty, _Err>{
|
|
_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(_Value)};
|
|
}
|
|
} else {
|
|
return expected<_Uty, _Err>{unexpect, _STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Ty, _Ty&>
|
|
constexpr auto transform_error(_Fn&& _Func) & {
|
|
static_assert(invocable<_Fn, _Err&>, "expected<T, E>::transform_error(F) requires that F is invocable with E. "
|
|
"(N4950 [expected.object.monadic]/27)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, _Err&>>;
|
|
static_assert(_Is_invoke_constructible<_Fn, _Err&>,
|
|
"expected<T, E>::transform_error(F) requires that the return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.object.monadic]/27)");
|
|
|
|
static_assert(_Check_unexpected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
return expected<_Ty, _Uty>{in_place, _Value};
|
|
} else {
|
|
return expected<_Ty, _Uty>{
|
|
_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_copy_constructible_v<_Ty>
|
|
constexpr auto transform_error(_Fn&& _Func) const& {
|
|
static_assert(invocable<_Fn, const _Err&>,
|
|
"expected<T, E>::transform_error(F) requires that F is invocable with E. "
|
|
"(N4950 [expected.object.monadic]/27)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, const _Err&>>;
|
|
static_assert(_Is_invoke_constructible<_Fn, const _Err&>,
|
|
"expected<T, E>::transform_error(F) requires that the return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.object.monadic]/27)");
|
|
|
|
static_assert(_Check_unexpected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
return expected<_Ty, _Uty>{in_place, _Value};
|
|
} else {
|
|
return expected<_Ty, _Uty>{
|
|
_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_move_constructible_v<_Ty>
|
|
constexpr auto transform_error(_Fn&& _Func) && {
|
|
static_assert(invocable<_Fn, _Err>, "expected<T, E>::transform_error(F) requires that F is invocable with E. "
|
|
"(N4950 [expected.object.monadic]/31)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, _Err>>;
|
|
static_assert(_Is_invoke_constructible<_Fn, _Err>,
|
|
"expected<T, E>::transform_error(F) requires that the return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.object.monadic]/31)");
|
|
|
|
static_assert(_Check_unexpected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
return expected<_Ty, _Uty>{in_place, _STD move(_Value)};
|
|
} else {
|
|
return expected<_Ty, _Uty>{_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func),
|
|
_STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Ty, const _Ty>
|
|
constexpr auto transform_error(_Fn&& _Func) const&& {
|
|
static_assert(invocable<_Fn, const _Err>,
|
|
"expected<T, E>::transform_error(F) requires that F is invocable with E. "
|
|
"(N4950 [expected.object.monadic]/31)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, const _Err>>;
|
|
static_assert(_Is_invoke_constructible<_Fn, const _Err>,
|
|
"expected<T, E>::transform_error(F) requires that the return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.object.monadic]/31)");
|
|
|
|
static_assert(_Check_unexpected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
return expected<_Ty, _Uty>{in_place, _STD move(_Value)};
|
|
} else {
|
|
return expected<_Ty, _Uty>{_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func),
|
|
_STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
// [expected.object.eq]
|
|
template <class _Uty, class _UErr>
|
|
requires (!is_void_v<_Uty>)
|
|
_NODISCARD friend constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right)
|
|
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Value == *_Right))
|
|
&& noexcept(_STD _Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
|
if (_Left._Has_value != _Right.has_value()) {
|
|
return false;
|
|
} else if (_Left._Has_value) {
|
|
return _Left._Value == *_Right;
|
|
} else {
|
|
return _Left._Unexpected == _Right.error();
|
|
}
|
|
}
|
|
|
|
template <class _Uty>
|
|
_NODISCARD friend constexpr bool operator==(const expected& _Left, const _Uty& _Right)
|
|
noexcept(noexcept(static_cast<bool>(_Left._Value == _Right))) /* strengthened */ {
|
|
if (_Left._Has_value) {
|
|
return static_cast<bool>(_Left._Value == _Right);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class _UErr>
|
|
_NODISCARD friend constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right)
|
|
noexcept(noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
|
if (_Left._Has_value) {
|
|
return false;
|
|
} else {
|
|
return static_cast<bool>(_Left._Unexpected == _Right.error());
|
|
}
|
|
}
|
|
|
|
private:
|
|
// These overloads force copy elision from the invoke call into _Value
|
|
template <class _Fn, class _Ux>
|
|
constexpr expected(_Construct_expected_from_invoke_result_tag, _Fn&& _Func, _Ux&& _Arg)
|
|
noexcept(noexcept(static_cast<_Ty>(_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Ux>(_Arg)))))
|
|
: _Value(_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Ux>(_Arg))), _Has_value{true} {}
|
|
|
|
// For when transform is called on an expected<void, E> and requires calling _Func with no arg
|
|
template <class _Fn>
|
|
constexpr expected(_Construct_expected_from_invoke_result_tag, _Fn&& _Func)
|
|
noexcept(noexcept(static_cast<_Ty>(_STD forward<_Fn>(_Func)()))) // f() is equivalent to invoke(f)
|
|
: _Value(_STD forward<_Fn>(_Func)()), _Has_value{true} {} // f() is equivalent to invoke(f)
|
|
|
|
template <class _Fn, class _Ux>
|
|
constexpr expected(_Construct_expected_from_invoke_result_tag, unexpect_t, _Fn&& _Func, _Ux&& _Arg)
|
|
noexcept(noexcept(static_cast<_Err>(_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Ux>(_Arg)))))
|
|
: _Unexpected(_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Ux>(_Arg))), _Has_value{false} {}
|
|
|
|
[[noreturn]] void _Throw_bad_expected_access_lv() const {
|
|
_THROW(bad_expected_access{_Unexpected});
|
|
}
|
|
[[noreturn]] void _Throw_bad_expected_access_rv() const {
|
|
_THROW(bad_expected_access{_STD move(_Unexpected)});
|
|
}
|
|
[[noreturn]] void _Throw_bad_expected_access_rv() {
|
|
_THROW(bad_expected_access{_STD move(_Unexpected)});
|
|
}
|
|
|
|
union {
|
|
_Ty _Value;
|
|
_Err _Unexpected;
|
|
};
|
|
bool _Has_value;
|
|
};
|
|
|
|
template <class _Err>
|
|
concept _Expected_unary_copy_assignable = is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err>;
|
|
|
|
template <class _Err>
|
|
concept _Expected_unary_move_assignable = is_move_assignable_v<_Err> && is_move_constructible_v<_Err>;
|
|
|
|
template <class _Ty, class _Err>
|
|
requires is_void_v<_Ty>
|
|
class expected<_Ty, _Err> {
|
|
private:
|
|
static_assert(_Check_unexpected_argument<_Err>::value);
|
|
|
|
template <class _UTy, class _UErr>
|
|
friend class expected;
|
|
|
|
template <class _Uty, class _UErr>
|
|
static constexpr bool _Allow_unwrapping = !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>&>
|
|
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>>
|
|
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>&>
|
|
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>>;
|
|
|
|
public:
|
|
using value_type = _Ty;
|
|
using error_type = _Err;
|
|
using unexpected_type = unexpected<_Err>;
|
|
|
|
template <class _Uty>
|
|
using rebind = expected<_Uty, error_type>;
|
|
|
|
// [expected.void.cons]
|
|
constexpr expected() noexcept : _Has_value(true) {}
|
|
|
|
constexpr expected(const expected& _Other) noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened
|
|
requires (!is_trivially_copy_constructible_v<_Err> && is_copy_constructible_v<_Err>)
|
|
: _Has_value(_Other._Has_value) {
|
|
if (!_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
|
|
}
|
|
}
|
|
|
|
expected(const expected&)
|
|
requires is_trivially_copy_constructible_v<_Err>
|
|
= default;
|
|
|
|
expected(const expected&) = delete;
|
|
|
|
constexpr expected(expected&& _Other) noexcept(is_nothrow_move_constructible_v<_Err>)
|
|
requires (!is_trivially_move_constructible_v<_Err> && is_move_constructible_v<_Err>)
|
|
: _Has_value(_Other._Has_value) {
|
|
if (!_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
|
|
}
|
|
}
|
|
|
|
expected(expected&&)
|
|
requires is_trivially_move_constructible_v<_Err>
|
|
= default;
|
|
|
|
template <class _Uty, class _UErr>
|
|
requires _Different_from<expected<_Uty, _UErr>, expected> && is_void_v<_Uty>
|
|
&& is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr>
|
|
constexpr explicit(!is_convertible_v<const _UErr&, _Err>) expected(const expected<_Uty, _UErr>& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
|
|
: _Has_value(_Other._Has_value) {
|
|
if (!_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
|
|
}
|
|
}
|
|
|
|
template <class _Uty, class _UErr>
|
|
requires _Different_from<expected<_Uty, _UErr>, expected> && is_void_v<_Uty> && is_constructible_v<_Err, _UErr>
|
|
&& _Allow_unwrapping<_Uty, _UErr>
|
|
constexpr explicit(!is_convertible_v<_UErr, _Err>) expected(expected<_Uty, _UErr>&& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Err, _UErr>) // strengthened
|
|
: _Has_value(_Other._Has_value) {
|
|
if (!_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
|
|
}
|
|
}
|
|
|
|
template <class _UErr>
|
|
requires is_constructible_v<_Err, const _UErr&>
|
|
constexpr explicit(!is_convertible_v<const _UErr&, _Err>) expected(const unexpected<_UErr>& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
|
|
: _Unexpected(_Other._Unexpected), _Has_value(false) {}
|
|
|
|
template <class _UErr>
|
|
requires is_constructible_v<_Err, _UErr>
|
|
constexpr explicit(!is_convertible_v<_UErr, _Err>) expected(unexpected<_UErr>&& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Err, _UErr>) // strengthened
|
|
: _Unexpected(_STD move(_Other._Unexpected)), _Has_value(false) {}
|
|
|
|
constexpr explicit expected(in_place_t) noexcept : _Has_value(true) {}
|
|
|
|
template <class... _Args>
|
|
requires is_constructible_v<_Err, _Args...>
|
|
constexpr explicit expected(unexpect_t, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
|
|
: _Unexpected(_STD forward<_Args>(_Vals)...), _Has_value(false) {}
|
|
|
|
template <class _Uty, class... _Args>
|
|
requires is_constructible_v<_Err, initializer_list<_Uty>&, _Args...>
|
|
constexpr explicit expected(unexpect_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals)
|
|
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Uty>&, _Args...>) // strengthened
|
|
: _Unexpected(_Ilist, _STD forward<_Args>(_Vals)...), _Has_value(false) {}
|
|
|
|
// [expected.void.dtor]
|
|
constexpr ~expected()
|
|
#ifndef __clang__ // TRANSITION, LLVM-59854
|
|
noexcept
|
|
#endif // ^^^ no workaround ^^^
|
|
{
|
|
if (!_Has_value) {
|
|
_Unexpected.~_Err();
|
|
}
|
|
}
|
|
|
|
~expected()
|
|
requires is_trivially_destructible_v<_Err>
|
|
= default;
|
|
|
|
// [expected.void.assign]
|
|
constexpr expected& operator=(const expected& _Other)
|
|
noexcept(is_nothrow_copy_constructible_v<_Err> && is_nothrow_copy_assignable_v<_Err>) // strengthened
|
|
requires _Expected_unary_copy_assignable<_Err>
|
|
{
|
|
if (_Has_value && _Other._Has_value) {
|
|
// nothing to do
|
|
} else if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
|
|
_Has_value = false;
|
|
} else if (_Other._Has_value) {
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Unexpected.~_Err();
|
|
}
|
|
_Has_value = true;
|
|
} else {
|
|
_Unexpected = _Other._Unexpected;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
expected& operator=(const expected&)
|
|
requires _Expected_unary_copy_assignable<_Err> && _Trivially_copy_constructible_assignable_destructible<_Err>
|
|
= default;
|
|
|
|
expected& operator=(const expected&) = delete;
|
|
|
|
constexpr expected& operator=(expected&& _Other)
|
|
noexcept(is_nothrow_move_constructible_v<_Err> && is_nothrow_move_assignable_v<_Err>)
|
|
requires _Expected_unary_move_assignable<_Err>
|
|
{
|
|
if (_Has_value && _Other._Has_value) {
|
|
// nothing to do
|
|
} else if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
|
|
_Has_value = false;
|
|
} else if (_Other._Has_value) {
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Unexpected.~_Err();
|
|
}
|
|
_Has_value = true;
|
|
} else {
|
|
_Unexpected = _STD move(_Other._Unexpected);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
expected& operator=(expected&&)
|
|
requires _Expected_unary_move_assignable<_Err> && _Trivially_move_constructible_assignable_destructible<_Err>
|
|
= default;
|
|
|
|
template <class _UErr>
|
|
requires is_constructible_v<_Err, const _UErr&> && is_assignable_v<_Err&, const _UErr&>
|
|
constexpr expected& operator=(const unexpected<_UErr>& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Err, const _UErr&>
|
|
&& is_nothrow_assignable_v<_Err&, const _UErr&>) /* strengthened */ {
|
|
if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
|
|
_Has_value = false;
|
|
} else {
|
|
_Unexpected = _Other._Unexpected;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <class _UErr>
|
|
requires is_constructible_v<_Err, _UErr> && is_assignable_v<_Err&, _UErr>
|
|
constexpr expected& operator=(unexpected<_UErr>&& _Other)
|
|
noexcept(is_nothrow_constructible_v<_Err, _UErr> && is_nothrow_assignable_v<_Err&, _UErr>) /* strengthened */ {
|
|
if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
|
|
_Has_value = false;
|
|
} else {
|
|
_Unexpected = _STD move(_Other._Unexpected);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
constexpr void emplace() noexcept {
|
|
if (!_Has_value) {
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Unexpected.~_Err();
|
|
}
|
|
_Has_value = true;
|
|
}
|
|
}
|
|
|
|
// [expected.void.swap]
|
|
constexpr void swap(expected& _Other)
|
|
noexcept(is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)
|
|
requires is_swappable_v<_Err> && is_move_constructible_v<_Err>
|
|
{
|
|
using _STD swap;
|
|
if (_Has_value && _Other._Has_value) {
|
|
// nothing
|
|
} else if (_Has_value) {
|
|
_STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Other._Unexpected.~_Err();
|
|
}
|
|
_Has_value = false;
|
|
_Other._Has_value = true;
|
|
} else if (_Other._Has_value) {
|
|
_STD construct_at(_STD addressof(_Other._Unexpected), _STD move(_Unexpected));
|
|
if constexpr (!is_trivially_destructible_v<_Err>) {
|
|
_Unexpected.~_Err();
|
|
}
|
|
_Has_value = true;
|
|
_Other._Has_value = false;
|
|
} else {
|
|
swap(_Unexpected, _Other._Unexpected); // intentional ADL
|
|
}
|
|
}
|
|
|
|
friend constexpr void swap(expected& _Left, expected& _Right)
|
|
noexcept(is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)
|
|
#if defined(__clang__) || defined(__EDG__) // TRANSITION, /permissive
|
|
requires is_swappable_v<_Err>
|
|
#else // ^^^ no workaround / workaround vvv
|
|
requires is_swappable<_Err>::value
|
|
#endif // ^^^ workaround ^^^
|
|
&& is_move_constructible_v<_Err>
|
|
{
|
|
_Left.swap(_Right);
|
|
}
|
|
|
|
// [expected.void.obs]
|
|
_NODISCARD constexpr explicit operator bool() const noexcept {
|
|
return _Has_value;
|
|
}
|
|
_NODISCARD constexpr bool has_value() const noexcept {
|
|
return _Has_value;
|
|
}
|
|
|
|
constexpr void operator*() const noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(_Has_value, "expected stores an error, not a value");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
}
|
|
|
|
constexpr void value() const& {
|
|
if (!_Has_value) {
|
|
_Throw_bad_expected_access_lv();
|
|
}
|
|
}
|
|
constexpr void value() && {
|
|
// TRANSITION, DevCom-1638273 and LLVM-53224
|
|
static_assert(is_copy_constructible_v<_Err>, "is_copy_constructible_v<E> must be true");
|
|
static_assert(is_move_constructible_v<_Err>, "is_move_constructible_v<E> must be true");
|
|
|
|
if (!_Has_value) {
|
|
_Throw_bad_expected_access_rv();
|
|
}
|
|
}
|
|
|
|
_NODISCARD constexpr const _Err& error() const& noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(!_Has_value, "expected stores a value, not an error");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _Unexpected;
|
|
}
|
|
_NODISCARD constexpr _Err& error() & noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(!_Has_value, "expected stores a value, not an error");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _Unexpected;
|
|
}
|
|
_NODISCARD constexpr const _Err&& error() const&& noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(!_Has_value, "expected stores a value, not an error");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _STD move(_Unexpected);
|
|
}
|
|
_NODISCARD constexpr _Err&& error() && noexcept {
|
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
|
_STL_VERIFY(!_Has_value, "expected stores a value, not an error");
|
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
|
return _STD move(_Unexpected);
|
|
}
|
|
|
|
template <class _Uty = _Err>
|
|
_NODISCARD constexpr _Err error_or(_Uty&& _Other) const& noexcept(
|
|
is_nothrow_copy_constructible_v<_Err> && is_nothrow_convertible_v<_Uty, _Err>) /* strengthened */ {
|
|
static_assert(
|
|
is_copy_constructible_v<_Err>, "is_copy_constructible_v<E> must be true. (N4950 [expected.void.obs]/9)");
|
|
static_assert(
|
|
is_convertible_v<_Uty, _Err>, "is_convertible_v<G, E> must be true. (N4950 [expected.void.obs]/9)");
|
|
|
|
if (_Has_value) {
|
|
return _STD forward<_Uty>(_Other);
|
|
} else {
|
|
return _Unexpected;
|
|
}
|
|
}
|
|
|
|
template <class _Uty = _Err>
|
|
_NODISCARD constexpr _Err error_or(_Uty&& _Other) && noexcept(
|
|
is_nothrow_move_constructible_v<_Err> && is_nothrow_convertible_v<_Uty, _Err>) /* strengthened */ {
|
|
static_assert(
|
|
is_move_constructible_v<_Err>, "is_move_constructible_v<E> must be true. (N4950 [expected.void.obs]/11)");
|
|
static_assert(
|
|
is_convertible_v<_Uty, _Err>, "is_convertible_v<G, E> must be true. (N4950 [expected.void.obs]/11)");
|
|
|
|
if (_Has_value) {
|
|
return _STD forward<_Uty>(_Other);
|
|
} else {
|
|
return _STD move(_Unexpected);
|
|
}
|
|
}
|
|
|
|
// [expected.void.monadic]
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Err, _Err&>
|
|
constexpr auto and_then(_Fn&& _Func) & {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<void, E>::and_then(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.void.monadic]/3)");
|
|
static_assert(is_same_v<typename _Uty::error_type, _Err>,
|
|
"expected<void, E>::and_then(F) requires the error type of the return type of F to be E. "
|
|
"(N4950 [expected.void.monadic]/3)");
|
|
|
|
if (_Has_value) {
|
|
return _STD forward<_Fn>(_Func)(); // f() is equivalent to invoke(f)
|
|
} else {
|
|
return _Uty{unexpect, _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_copy_constructible_v<_Err>
|
|
constexpr auto and_then(_Fn&& _Func) const& {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<void, E>::and_then(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.void.monadic]/3)");
|
|
static_assert(is_same_v<typename _Uty::error_type, _Err>,
|
|
"expected<void, E>::and_then(F) requires the error type of the return type of F to be E. "
|
|
"(N4950 [expected.void.monadic]/3)");
|
|
|
|
if (_Has_value) {
|
|
return _STD forward<_Fn>(_Func)(); // f() is equivalent to invoke(f)
|
|
} else {
|
|
return _Uty{unexpect, _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_move_constructible_v<_Err>
|
|
constexpr auto and_then(_Fn&& _Func) && {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<void, E>::and_then(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.void.monadic]/7)");
|
|
static_assert(is_same_v<typename _Uty::error_type, _Err>,
|
|
"expected<void, E>::and_then(F) requires the error type of the return type of F to be E. "
|
|
"(N4950 [expected.void.monadic]/7)");
|
|
|
|
if (_Has_value) {
|
|
return _STD forward<_Fn>(_Func)(); // f() is equivalent to invoke(f)
|
|
} else {
|
|
return _Uty{unexpect, _STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Err, const _Err>
|
|
constexpr auto and_then(_Fn&& _Func) const&& {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<void, E>::and_then(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.void.monadic]/7)");
|
|
static_assert(is_same_v<typename _Uty::error_type, _Err>,
|
|
"expected<void, E>::and_then(F) requires the error type of the return type of F to be E. "
|
|
"(N4950 [expected.void.monadic]/7)");
|
|
|
|
if (_Has_value) {
|
|
return _STD forward<_Fn>(_Func)(); // f() is equivalent to invoke(f)
|
|
} else {
|
|
return _Uty{unexpect, _STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
constexpr auto or_else(_Fn&& _Func) & {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, _Err&>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<void, E>::or_else(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.void.monadic]/10)");
|
|
static_assert(is_same_v<typename _Uty::value_type, _Ty>,
|
|
"expected<void, E>::or_else(F) requires the value type of the return type of F to be T. "
|
|
"(N4950 [expected.void.monadic]/10)");
|
|
|
|
if (_Has_value) {
|
|
return _Uty{};
|
|
} else {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _Unexpected);
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
constexpr auto or_else(_Fn&& _Func) const& {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, const _Err&>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<void, E>::or_else(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.void.monadic]/10)");
|
|
static_assert(is_same_v<typename _Uty::value_type, _Ty>,
|
|
"expected<void, E>::or_else(F) requires the value type of the return type of F to be T. "
|
|
"(N4950 [expected.void.monadic]/10)");
|
|
|
|
if (_Has_value) {
|
|
return _Uty{};
|
|
} else {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _Unexpected);
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
constexpr auto or_else(_Fn&& _Func) && {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, _Err>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<void, E>::or_else(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.void.monadic]/13)");
|
|
static_assert(is_same_v<typename _Uty::value_type, _Ty>,
|
|
"expected<void, E>::or_else(F) requires the value type of the return type of F to be T. "
|
|
"(N4950 [expected.void.monadic]/13)");
|
|
|
|
if (_Has_value) {
|
|
return _Uty{};
|
|
} else {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Unexpected));
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
constexpr auto or_else(_Fn&& _Func) const&& {
|
|
using _Uty = remove_cvref_t<invoke_result_t<_Fn, const _Err>>;
|
|
|
|
static_assert(_Is_specialization_v<_Uty, expected>,
|
|
"expected<void, E>::or_else(F) requires the return type of F to be a specialization of expected. "
|
|
"(N4950 [expected.void.monadic]/13)");
|
|
static_assert(is_same_v<typename _Uty::value_type, _Ty>,
|
|
"expected<void, E>::or_else(F) requires the value type of the return type of F to be T. "
|
|
"(N4950 [expected.void.monadic]/13)");
|
|
|
|
if (_Has_value) {
|
|
return _Uty{};
|
|
} else {
|
|
return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Unexpected));
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Err, _Err&>
|
|
constexpr auto transform(_Fn&& _Func) & {
|
|
static_assert(invocable<_Fn>, "expected<void, E>::transform(F) requires that F is invocable with no arguments. "
|
|
"(N4950 [expected.void.monadic]/17)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn>>;
|
|
|
|
if constexpr (!is_void_v<_Uty>) {
|
|
static_assert(_Is_invoke_constructible<_Fn>, "expected<void, E>::transform(F) requires that the return "
|
|
"type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.void.monadic]/17)");
|
|
}
|
|
static_assert(_Check_expected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
if constexpr (is_void_v<_Uty>) {
|
|
_STD forward<_Fn>(_Func)(); // f() is equivalent to invoke(f)
|
|
return expected<_Uty, _Err>{};
|
|
} else {
|
|
return expected<_Uty, _Err>{_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func)};
|
|
}
|
|
} else {
|
|
return expected<_Uty, _Err>{unexpect, _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_copy_constructible_v<_Err>
|
|
constexpr auto transform(_Fn&& _Func) const& {
|
|
static_assert(invocable<_Fn>, "expected<void, E>::transform(F) requires that F is invocable with no arguments. "
|
|
"(N4950 [expected.void.monadic]/17)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn>>;
|
|
|
|
if constexpr (!is_void_v<_Uty>) {
|
|
static_assert(_Is_invoke_constructible<_Fn>, "expected<void, E>::transform(F) requires that the return "
|
|
"type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.void.monadic]/17)");
|
|
}
|
|
static_assert(_Check_expected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
if constexpr (is_void_v<_Uty>) {
|
|
_STD forward<_Fn>(_Func)(); // f() is equivalent to invoke(f)
|
|
return expected<_Uty, _Err>{};
|
|
} else {
|
|
return expected<_Uty, _Err>{_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func)};
|
|
}
|
|
} else {
|
|
return expected<_Uty, _Err>{unexpect, _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_move_constructible_v<_Err>
|
|
constexpr auto transform(_Fn&& _Func) && {
|
|
static_assert(invocable<_Fn>, "expected<void, E>::transform(F) requires that F is invocable with no arguments. "
|
|
"(N4950 [expected.void.monadic]/21)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn>>;
|
|
|
|
if constexpr (!is_void_v<_Uty>) {
|
|
static_assert(_Is_invoke_constructible<_Fn>, "expected<void, E>::transform(F) requires that the return "
|
|
"type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.void.monadic]/21)");
|
|
}
|
|
static_assert(_Check_expected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
if constexpr (is_void_v<_Uty>) {
|
|
_STD forward<_Fn>(_Func)(); // f() is equivalent to invoke(f)
|
|
return expected<_Uty, _Err>{};
|
|
} else {
|
|
return expected<_Uty, _Err>{_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func)};
|
|
}
|
|
} else {
|
|
return expected<_Uty, _Err>{unexpect, _STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
requires is_constructible_v<_Err, const _Err>
|
|
constexpr auto transform(_Fn&& _Func) const&& {
|
|
static_assert(invocable<_Fn>, "expected<void, E>::transform(F) requires that F is invocable with no arguments. "
|
|
"(N4950 [expected.void.monadic]/21)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn>>;
|
|
|
|
if constexpr (!is_void_v<_Uty>) {
|
|
static_assert(_Is_invoke_constructible<_Fn>, "expected<void, E>::transform(F) requires that the return "
|
|
"type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.void.monadic]/21)");
|
|
}
|
|
static_assert(_Check_expected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
if constexpr (is_void_v<_Uty>) {
|
|
_STD forward<_Fn>(_Func)(); // f() is equivalent to invoke(f)
|
|
return expected<_Uty, _Err>{};
|
|
} else {
|
|
return expected<_Uty, _Err>{_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func)};
|
|
}
|
|
} else {
|
|
return expected<_Uty, _Err>{unexpect, _STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
constexpr auto transform_error(_Fn&& _Func) & {
|
|
static_assert(invocable<_Fn, _Err&>,
|
|
"expected<void, E>::transform_error(F) requires that F is invocable with E. "
|
|
"(N4950 [expected.void.monadic]/24)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, _Err&>>;
|
|
static_assert(_Is_invoke_constructible<_Fn, _Err&>, "expected<void, E>::transform_error(F) requires that the "
|
|
"return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.void.monadic]/24)");
|
|
|
|
static_assert(_Check_unexpected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
return expected<_Ty, _Uty>{};
|
|
} else {
|
|
return expected<_Ty, _Uty>{
|
|
_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
constexpr auto transform_error(_Fn&& _Func) const& {
|
|
static_assert(invocable<_Fn, const _Err&>,
|
|
"expected<void, E>::transform_error(F) requires that F is invocable with E. "
|
|
"(N4950 [expected.void.monadic]/24)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, const _Err&>>;
|
|
static_assert(_Is_invoke_constructible<_Fn, const _Err&>,
|
|
"expected<void, E>::transform_error(F) requires that the "
|
|
"return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.void.monadic]/24)");
|
|
|
|
static_assert(_Check_unexpected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
return expected<_Ty, _Uty>{};
|
|
} else {
|
|
return expected<_Ty, _Uty>{
|
|
_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _Unexpected};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
constexpr auto transform_error(_Fn&& _Func) && {
|
|
static_assert(invocable<_Fn, _Err>,
|
|
"expected<void, E>::transform_error(F) requires that F is invocable with E. "
|
|
"(N4950 [expected.void.monadic]/27)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, _Err>>;
|
|
static_assert(_Is_invoke_constructible<_Fn, _Err>, "expected<void, E>::transform_error(F) requires that the "
|
|
"return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.void.monadic]/27)");
|
|
|
|
static_assert(_Check_unexpected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
return expected<_Ty, _Uty>{};
|
|
} else {
|
|
return expected<_Ty, _Uty>{_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func),
|
|
_STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
template <class _Fn>
|
|
constexpr auto transform_error(_Fn&& _Func) const&& {
|
|
static_assert(invocable<_Fn, const _Err>,
|
|
"expected<void, E>::transform_error(F) requires that F is invocable with E. "
|
|
"(N4950 [expected.void.monadic]/27)");
|
|
using _Uty = remove_cv_t<invoke_result_t<_Fn, const _Err>>;
|
|
static_assert(_Is_invoke_constructible<_Fn, const _Err>,
|
|
"expected<void, E>::transform_error(F) requires that the "
|
|
"return type of F is constructible with the result of "
|
|
"invoking f. (N4950 [expected.void.monadic]/27)");
|
|
|
|
static_assert(_Check_unexpected_argument<_Uty>::value);
|
|
|
|
if (_Has_value) {
|
|
return expected<_Ty, _Uty>{};
|
|
} else {
|
|
return expected<_Ty, _Uty>{_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func),
|
|
_STD move(_Unexpected)};
|
|
}
|
|
}
|
|
|
|
// [expected.void.eq]
|
|
template <class _Uty, class _UErr>
|
|
requires is_void_v<_Uty>
|
|
_NODISCARD friend constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right)
|
|
noexcept(noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
|
if (_Left._Has_value != _Right.has_value()) {
|
|
return false;
|
|
} else {
|
|
return _Left._Has_value || static_cast<bool>(_Left._Unexpected == _Right.error());
|
|
}
|
|
}
|
|
|
|
template <class _UErr>
|
|
_NODISCARD friend constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right)
|
|
noexcept(noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
|
if (_Left._Has_value) {
|
|
return false;
|
|
} else {
|
|
return static_cast<bool>(_Left._Unexpected == _Right.error());
|
|
}
|
|
}
|
|
|
|
private:
|
|
template <class _Fn, class _Ux>
|
|
constexpr expected(_Construct_expected_from_invoke_result_tag, unexpect_t, _Fn&& _Func, _Ux&& _Arg)
|
|
noexcept(noexcept(_Err(_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Ux>(_Arg)))))
|
|
: _Unexpected(_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Ux>(_Arg))), _Has_value{false} {}
|
|
|
|
[[noreturn]] void _Throw_bad_expected_access_lv() const {
|
|
_THROW(bad_expected_access{_Unexpected});
|
|
}
|
|
[[noreturn]] void _Throw_bad_expected_access_rv() {
|
|
_THROW(bad_expected_access{_STD move(_Unexpected)});
|
|
}
|
|
|
|
union {
|
|
_Err _Unexpected;
|
|
};
|
|
bool _Has_value;
|
|
};
|
|
|
|
_STD_END
|
|
|
|
#pragma pop_macro("new")
|
|
_STL_RESTORE_CLANG_WARNINGS
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
#endif // ^^^ _HAS_CXX23 ^^^
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
#endif // _EXPECTED_
|