зеркало из https://github.com/microsoft/STL.git
Implement P2505R5 Monadic Functions For std::expected (#3361)
Co-authored-by: Casey Carter <Casey@Carter.net> Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
Родитель
1abaa14ee5
Коммит
8f912858db
847
stl/inc/expected
847
stl/inc/expected
|
@ -30,12 +30,12 @@ class unexpected;
|
|||
|
||||
template <class _Err>
|
||||
struct _Check_unexpected_argument : true_type {
|
||||
static_assert(is_object_v<_Err>, "E must be an object type. (N4910 [expected.un.object.general]/1)");
|
||||
static_assert(!is_array_v<_Err>, "E must not be an array type. (N4910 [expected.un.object.general]/1)");
|
||||
static_assert(!is_const_v<_Err>, "E must not be const. (N4910 [expected.un.object.general]/1)");
|
||||
static_assert(!is_volatile_v<_Err>, "E must not be volatile. (N4910 [expected.un.object.general]/1)");
|
||||
static_assert(is_object_v<_Err>, "E must be an object type. (N4928 [expected.un.general]/2)");
|
||||
static_assert(!is_array_v<_Err>, "E must not be an array type. (N4928 [expected.un.general]/2)");
|
||||
static_assert(!is_const_v<_Err>, "E must not be const. (N4928 [expected.un.general]/2)");
|
||||
static_assert(!is_volatile_v<_Err>, "E must not be volatile. (N4928 [expected.un.general]/2)");
|
||||
static_assert(!_Is_specialization_v<_Err, unexpected>,
|
||||
"E must not be a specialization of unexpected. (N4910 [expected.un.object.general]/1)");
|
||||
"E must not be a specialization of unexpected. (N4928 [expected.un.general]/2)");
|
||||
};
|
||||
|
||||
// [expected.un.general]
|
||||
|
@ -47,8 +47,7 @@ class unexpected {
|
|||
friend class expected;
|
||||
|
||||
public:
|
||||
// [expected.un.ctor]
|
||||
|
||||
// [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>)
|
||||
|
@ -96,7 +95,7 @@ public:
|
|||
// [expected.un.eq]
|
||||
template <class _UErr>
|
||||
_NODISCARD_FRIEND constexpr bool operator==(const unexpected& _Left, const unexpected<_UErr>& _Right) noexcept(
|
||||
noexcept(_Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) { // strengthened
|
||||
noexcept(_Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
||||
return _Left._Unexpected == _Right.error();
|
||||
}
|
||||
|
||||
|
@ -160,17 +159,32 @@ _EXPORT_STD struct unexpect_t {
|
|||
|
||||
_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. (N4928 [expected.object.general]/2)");
|
||||
static_assert(!is_function_v<_Ty>, "T must not be a function type. (N4928 [expected.object.general]/2)");
|
||||
static_assert(!is_array_v<_Ty>, "T must not be an array type. (N4928 [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. (N4928 [expected.object.general]/2)");
|
||||
static_assert(!is_same_v<remove_cv_t<_Ty>, unexpect_t>,
|
||||
"T must not be (possibly cv-qualified) unexpect_t. (N4928 [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. (N4928 [expected.object.general]/2)");
|
||||
};
|
||||
|
||||
_EXPORT_STD template <class _Ty, class _Err>
|
||||
class expected {
|
||||
static_assert(!is_reference_v<_Ty>, "T must not be a reference type. (N4910 [expected.object.general]/2)");
|
||||
static_assert(!is_function_v<_Ty>, "T must not be a function type. (N4910 [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. (N4910 [expected.object.general]/2)");
|
||||
static_assert(!is_same_v<remove_cv_t<_Ty>, unexpect_t>,
|
||||
"T must not be (possibly cv-qualified) unexpect_t. (N4910 [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. (N4910 [expected.object.general]/2)");
|
||||
|
||||
static_assert(_Check_expected_argument<_Ty>::value);
|
||||
static_assert(_Check_unexpected_argument<_Err>::value);
|
||||
|
||||
template <class _UTy, class _UErr>
|
||||
|
@ -184,7 +198,7 @@ public:
|
|||
template <class _Uty>
|
||||
using rebind = expected<_Uty, error_type>;
|
||||
|
||||
// [expected.object.ctor]
|
||||
// [expected.object.cons]
|
||||
constexpr expected() noexcept(is_nothrow_default_constructible_v<_Ty>) // strengthened
|
||||
requires is_default_constructible_v<_Ty>
|
||||
: _Value(), _Has_value(true) {}
|
||||
|
@ -417,7 +431,7 @@ public:
|
|||
&& (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
|
||||
is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_assignable_v<_Ty&, _Uty>) /* strengthened */ {
|
||||
if (_Has_value) {
|
||||
_Value = _STD forward<_Uty>(_Other);
|
||||
} else {
|
||||
|
@ -433,7 +447,8 @@ public:
|
|||
&& (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
|
||||
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;
|
||||
|
@ -449,7 +464,7 @@ public:
|
|||
&& (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
|
||||
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;
|
||||
|
@ -658,11 +673,11 @@ public:
|
|||
|
||||
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
|
||||
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. (N4910 [expected.object.obs]/16)");
|
||||
is_copy_constructible_v<_Ty>, "is_copy_constructible_v<T> must be true. (N4928 [expected.object.obs]/16)");
|
||||
static_assert(
|
||||
is_convertible_v<_Uty, _Ty>, "is_convertible_v<U, T> must be true. (N4910 [expected.object.obs]/16)");
|
||||
is_convertible_v<_Uty, _Ty>, "is_convertible_v<U, T> must be true. (N4928 [expected.object.obs]/16)");
|
||||
|
||||
if (_Has_value) {
|
||||
return _Value;
|
||||
|
@ -672,11 +687,11 @@ public:
|
|||
}
|
||||
template <class _Uty>
|
||||
_NODISCARD constexpr _Ty value_or(_Uty&& _Other) && noexcept(
|
||||
is_nothrow_move_constructible_v<_Ty>&& is_nothrow_convertible_v<_Uty, _Ty>) { // strengthened
|
||||
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. (N4910 [expected.object.obs]/18)");
|
||||
is_move_constructible_v<_Ty>, "is_move_constructible_v<T> must be true. (N4928 [expected.object.obs]/18)");
|
||||
static_assert(
|
||||
is_convertible_v<_Uty, _Ty>, "is_convertible_v<U, T> must be true. (N4910 [expected.object.obs]/18)");
|
||||
is_convertible_v<_Uty, _Ty>, "is_convertible_v<U, T> must be true. (N4928 [expected.object.obs]/18)");
|
||||
|
||||
if (_Has_value) {
|
||||
return _STD move(_Value);
|
||||
|
@ -685,13 +700,385 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// [expected.object.eq]
|
||||
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. (N4928 [expected.object.obs]/20)");
|
||||
static_assert(
|
||||
is_convertible_v<_Uty, _Err>, "is_convertible_v<G, E> must be true. (N4928 [expected.object.obs]/20)");
|
||||
|
||||
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. (N4928 [expected.object.obs]/22)");
|
||||
static_assert(
|
||||
is_convertible_v<_Uty, _Err>, "is_convertible_v<G, E> must be true. (N4928 [expected.object.obs]/22)");
|
||||
|
||||
if (_Has_value) {
|
||||
return _STD forward<_Uty>(_Other);
|
||||
} else {
|
||||
return _STD move(_Unexpected);
|
||||
}
|
||||
}
|
||||
|
||||
// [expected.object.monadic]
|
||||
template <class _Fn>
|
||||
requires is_copy_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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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_move_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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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_copy_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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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_move_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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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_copy_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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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_move_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. "
|
||||
"(N4928 [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. (N4928 [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_copy_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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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_move_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. "
|
||||
"(N4928 [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. (N4928 [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(_Fake_copy_init<bool>(_Left._Value == *_Right)) && noexcept(
|
||||
_Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) { // strengthened
|
||||
_Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
||||
if (_Left._Has_value != _Right.has_value()) {
|
||||
return false;
|
||||
} else if (_Left._Has_value) {
|
||||
|
@ -703,7 +1090,7 @@ public:
|
|||
|
||||
template <class _Uty>
|
||||
_NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const _Uty& _Right) noexcept(
|
||||
noexcept(static_cast<bool>(_Left._Value == _Right))) { // strengthened
|
||||
noexcept(static_cast<bool>(_Left._Value == _Right))) /* strengthened */ {
|
||||
if (_Left._Has_value) {
|
||||
return static_cast<bool>(_Left._Value == _Right);
|
||||
} else {
|
||||
|
@ -713,7 +1100,7 @@ public:
|
|||
|
||||
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
|
||||
noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
||||
if (_Left._Has_value) {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -722,6 +1109,23 @@ public:
|
|||
}
|
||||
|
||||
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});
|
||||
}
|
||||
|
@ -758,7 +1162,7 @@ public:
|
|||
template <class _Uty>
|
||||
using rebind = expected<_Uty, error_type>;
|
||||
|
||||
// [expected.void.ctor]
|
||||
// [expected.void.cons]
|
||||
constexpr expected() noexcept : _Has_value(true) {}
|
||||
|
||||
constexpr expected(const expected& _Other) noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened
|
||||
|
@ -898,7 +1302,8 @@ public:
|
|||
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
|
||||
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;
|
||||
|
@ -912,7 +1317,7 @@ public:
|
|||
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
|
||||
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;
|
||||
|
@ -1033,11 +1438,376 @@ public:
|
|||
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. (N4928 [expected.void.obs]/9)");
|
||||
static_assert(
|
||||
is_convertible_v<_Uty, _Err>, "is_convertible_v<G, E> must be true. (N4928 [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. (N4928 [expected.void.obs]/11)");
|
||||
static_assert(
|
||||
is_convertible_v<_Uty, _Err>, "is_convertible_v<G, E> must be true. (N4928 [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_copy_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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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_move_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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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. "
|
||||
"(N4928 [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_copy_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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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_move_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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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. "
|
||||
"(N4928 [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. (N4928 [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
|
||||
noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
||||
if (_Left._Has_value != _Right.has_value()) {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -1047,7 +1817,7 @@ public:
|
|||
|
||||
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
|
||||
noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
|
||||
if (_Left._Has_value) {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -1056,6 +1826,11 @@ public:
|
|||
}
|
||||
|
||||
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});
|
||||
}
|
||||
|
|
|
@ -347,6 +347,7 @@
|
|||
// P2474R2 views::repeat
|
||||
// P2494R2 Relaxing Range Adaptors To Allow Move-Only Types
|
||||
// P2499R0 string_view Range Constructor Should Be explicit
|
||||
// P2505R5 Monadic Functions For expected
|
||||
// P2549R1 unexpected<E>::error()
|
||||
// P2602R2 Poison Pills Are Too Toxic
|
||||
|
||||
|
@ -1679,7 +1680,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
|
|||
|
||||
#ifdef __cpp_lib_concepts
|
||||
#define __cpp_lib_containers_ranges 202202L
|
||||
#define __cpp_lib_expected 202202L
|
||||
#define __cpp_lib_expected 202211L
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
#define __cpp_lib_forward_like 202207L
|
||||
|
|
|
@ -82,6 +82,9 @@ std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_deallocate_ma
|
|||
# Too many constexpr operations
|
||||
std/utilities/charconv/charconv.to.chars/integral.pass.cpp FAIL
|
||||
|
||||
# libc++ has not implemented P2505R5: "Monadic Functions for std::expected"
|
||||
std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp FAIL
|
||||
|
||||
|
||||
# *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX ***
|
||||
# Tracked by VSO-593630 "<filesystem> Enable libcxx filesystem tests"
|
||||
|
|
|
@ -82,6 +82,9 @@ utilities\utility\mem.res\mem.res.pool\mem.res.pool.mem\unsync_deallocate_matche
|
|||
# Too many constexpr operations
|
||||
utilities\charconv\charconv.to.chars\integral.pass.cpp
|
||||
|
||||
# libc++ has not implemented P2505R5: "Monadic Functions for std::expected"
|
||||
language.support\support.limits\support.limits.general\expected.version.compile.pass.cpp
|
||||
|
||||
|
||||
# *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX ***
|
||||
# Tracked by VSO-593630 "<filesystem> Enable libcxx filesystem tests"
|
||||
|
|
|
@ -590,6 +590,7 @@ tests\P2467R1_exclusive_mode_fstreams
|
|||
tests\P2474R2_views_repeat
|
||||
tests\P2474R2_views_repeat_death
|
||||
tests\P2494R2_move_only_range_adaptors
|
||||
tests\P2505R5_monadic_functions_for_std_expected
|
||||
tests\P2517R1_apply_conditional_noexcept
|
||||
tests\VSO_0000000_allocator_propagation
|
||||
tests\VSO_0000000_any_calling_conventions
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_latest_matrix.lst
|
|
@ -0,0 +1,381 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <cassert>
|
||||
#include <expected>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace detail {
|
||||
static constexpr bool permissive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class>
|
||||
struct DependentBase {
|
||||
static constexpr bool permissive() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Derived : DependentBase<T> {
|
||||
static constexpr bool test() {
|
||||
return permissive();
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
constexpr bool is_permissive = detail::Derived<int>::test();
|
||||
|
||||
enum class IsNothrowConstructible : bool { Not, Yes };
|
||||
enum class IsNothrowConvertible : bool { Not, Yes };
|
||||
|
||||
template <class E>
|
||||
[[nodiscard]] constexpr bool IsYes(const E e) noexcept {
|
||||
return e == E::Yes;
|
||||
}
|
||||
|
||||
struct convertible {
|
||||
constexpr convertible(const int val) noexcept : _val(val) {}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const int other) const noexcept {
|
||||
return other == _val;
|
||||
}
|
||||
|
||||
int _val = 0;
|
||||
};
|
||||
|
||||
struct Immovable {
|
||||
constexpr Immovable(const int x) : v(x) {}
|
||||
Immovable(const Immovable&) = delete;
|
||||
Immovable(Immovable&&) = delete;
|
||||
Immovable& operator=(const Immovable&) = delete;
|
||||
Immovable& operator=(Immovable&&) = delete;
|
||||
constexpr ~Immovable() = default;
|
||||
|
||||
int v;
|
||||
};
|
||||
|
||||
struct Thingy {
|
||||
expected<int, int> x;
|
||||
constexpr int member_func() const {
|
||||
return 66;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Expected>
|
||||
constexpr void test_impl(Expected&& engaged, Expected&& unengaged) {
|
||||
assert(engaged.has_value());
|
||||
assert(!unengaged.has_value());
|
||||
static_assert(is_same_v<typename remove_cvref_t<Expected>::error_type, int>);
|
||||
using Val = typename remove_cvref_t<Expected>::value_type;
|
||||
|
||||
const auto succeed = [](auto...) { return expected<int, int>{33}; };
|
||||
const auto fail = [](auto...) { return expected<int, int>{unexpect, 44}; };
|
||||
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).and_then(succeed);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(result == 33);
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).and_then(succeed);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 22);
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).and_then(fail);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 44);
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).and_then(fail);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 22);
|
||||
}
|
||||
|
||||
if constexpr (!is_void_v<Val>) {
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).and_then(&Thingy::x);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(result == 11);
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).and_then(&Thingy::x);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 22);
|
||||
}
|
||||
}
|
||||
|
||||
const auto f = [](auto...) { return 55; };
|
||||
const auto immov = [](auto...) { return Immovable{88}; };
|
||||
const auto to_void = [](auto...) { return; };
|
||||
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).transform(f);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(result == 55);
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).transform(f);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 22);
|
||||
}
|
||||
|
||||
if constexpr (!is_void_v<Val>) {
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).transform(&Thingy::member_func);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(result == 66);
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).transform(&Thingy::member_func);
|
||||
static_assert(is_same_v<decltype(result), expected<int, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 22);
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (!is_permissive) { // TRANSITION, VSO-1734935
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).transform(immov);
|
||||
static_assert(is_same_v<decltype(result), expected<Immovable, int>>);
|
||||
assert(result->v == 88);
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).transform(immov);
|
||||
static_assert(is_same_v<decltype(result), expected<Immovable, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 22);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).transform(to_void);
|
||||
static_assert(is_same_v<decltype(result), expected<void, int>>);
|
||||
assert(result);
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).transform(to_void);
|
||||
static_assert(is_same_v<decltype(result), expected<void, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 22);
|
||||
}
|
||||
|
||||
const auto to_thingy = [](int i) { return Thingy{i}; };
|
||||
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).transform_error(to_thingy);
|
||||
static_assert(is_same_v<decltype(result), expected<Val, Thingy>>);
|
||||
assert(result);
|
||||
if constexpr (!is_void_v<Val>) {
|
||||
assert(result->x == 11);
|
||||
}
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).transform_error(to_thingy);
|
||||
static_assert(is_same_v<decltype(result), expected<Val, Thingy>>);
|
||||
assert(!result);
|
||||
assert(result.error().x == 22);
|
||||
}
|
||||
{
|
||||
decltype(auto) result =
|
||||
forward<Expected>(engaged).transform_error(to_thingy).transform_error(&Thingy::member_func);
|
||||
static_assert(is_same_v<decltype(result), expected<Val, int>>);
|
||||
assert(result);
|
||||
if constexpr (!is_void_v<Val>) {
|
||||
assert(result->x == 11);
|
||||
}
|
||||
}
|
||||
{
|
||||
decltype(auto) result =
|
||||
forward<Expected>(unengaged).transform_error(to_thingy).transform_error(&Thingy::member_func);
|
||||
static_assert(is_same_v<decltype(result), expected<Val, int>>);
|
||||
assert(!result);
|
||||
assert(result.error() == 66);
|
||||
}
|
||||
|
||||
if constexpr (!is_permissive) { // TRANSITION, VSO-1734935
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).transform_error(immov);
|
||||
static_assert(is_same_v<decltype(result), expected<Val, Immovable>>);
|
||||
assert(result);
|
||||
if constexpr (!is_void_v<Val>) {
|
||||
assert(result->x == 11);
|
||||
}
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).transform_error(immov);
|
||||
static_assert(is_same_v<decltype(result), expected<Val, Immovable>>);
|
||||
assert(!result);
|
||||
assert(result.error().v == 88);
|
||||
}
|
||||
}
|
||||
|
||||
const auto to_expected_thingy = [](auto...) {
|
||||
if constexpr (is_void_v<Val>) {
|
||||
return expected<void, int>{};
|
||||
} else {
|
||||
return expected<Val, int>{Thingy{77}};
|
||||
}
|
||||
};
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(engaged).or_else(to_expected_thingy);
|
||||
static_assert(is_same_v<decltype(result), expected<Val, int>>);
|
||||
assert(result);
|
||||
if constexpr (!is_void_v<Val>) {
|
||||
assert(result.value().x == 11);
|
||||
}
|
||||
}
|
||||
{
|
||||
decltype(auto) result = forward<Expected>(unengaged).or_else(to_expected_thingy);
|
||||
static_assert(is_same_v<decltype(result), expected<Val, int>>);
|
||||
assert(result);
|
||||
if constexpr (!is_void_v<Val>) {
|
||||
assert(result.value().x == 77);
|
||||
}
|
||||
}
|
||||
|
||||
engaged.transform([](auto...) { return ""; });
|
||||
}
|
||||
|
||||
template <IsNothrowConstructible nothrowConstructible, IsNothrowConvertible nothrowConvertible>
|
||||
constexpr void test_error_or() {
|
||||
constexpr bool construction_is_noexcept = IsYes(nothrowConstructible);
|
||||
constexpr bool conversion_is_noexcept = IsYes(nothrowConvertible);
|
||||
constexpr bool should_be_noexcept = construction_is_noexcept && conversion_is_noexcept;
|
||||
|
||||
struct payload_error_or {
|
||||
constexpr payload_error_or() noexcept : _val(55) {}
|
||||
constexpr payload_error_or(const int val) noexcept : _val(val) {}
|
||||
constexpr payload_error_or(const payload_error_or& other) noexcept(construction_is_noexcept)
|
||||
: _val(other._val + 2) {}
|
||||
constexpr payload_error_or(payload_error_or&& other) noexcept(construction_is_noexcept)
|
||||
: _val(other._val + 3) {}
|
||||
constexpr payload_error_or(const convertible& val) noexcept(conversion_is_noexcept) : _val(val._val + 4) {}
|
||||
constexpr payload_error_or(convertible&& val) noexcept(conversion_is_noexcept) : _val(val._val + 5) {}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const payload_error_or&) const noexcept = default;
|
||||
|
||||
int _val;
|
||||
};
|
||||
|
||||
{ // with payload argument
|
||||
using Expected = expected<int, payload_error_or>;
|
||||
|
||||
Expected with_error{unexpect, 42};
|
||||
const Expected const_with_error{unexpect, 1337};
|
||||
assert(with_error.error_or(payload_error_or{1}) == 42 + 2);
|
||||
assert(const_with_error.error_or(payload_error_or{1}) == 1337 + 2);
|
||||
static_assert(noexcept(with_error.error_or(payload_error_or{1})) == construction_is_noexcept);
|
||||
static_assert(noexcept(const_with_error.error_or(payload_error_or{1})) == construction_is_noexcept);
|
||||
|
||||
assert(move(with_error).error_or(payload_error_or{1}) == 42 + 3);
|
||||
assert(move(const_with_error).error_or(payload_error_or{1}) == 1337 + 2);
|
||||
static_assert(noexcept(move(with_error).error_or(payload_error_or{1})) == construction_is_noexcept);
|
||||
static_assert(noexcept(move(const_with_error).error_or(payload_error_or{1})) == construction_is_noexcept);
|
||||
|
||||
const payload_error_or input{2000};
|
||||
Expected with_value{in_place, 42};
|
||||
const Expected const_with_value{in_place, 1337};
|
||||
assert(with_value.error_or(payload_error_or{1}) == 1 + 3);
|
||||
assert(const_with_value.error_or(input) == 2000 + 2);
|
||||
static_assert(noexcept(with_value.error_or(payload_error_or{1})) == construction_is_noexcept);
|
||||
static_assert(noexcept(const_with_value.error_or(input)) == construction_is_noexcept);
|
||||
|
||||
assert(move(with_value).error_or(payload_error_or{1}) == 1 + 3);
|
||||
assert(move(const_with_value).error_or(input) == 2000 + 2);
|
||||
static_assert(noexcept(move(with_value).error_or(payload_error_or{1})) == construction_is_noexcept);
|
||||
static_assert(noexcept(move(const_with_value).error_or(input)) == construction_is_noexcept);
|
||||
}
|
||||
|
||||
{ // with convertible argument
|
||||
using Expected = expected<int, payload_error_or>;
|
||||
|
||||
Expected with_error{unexpect, 42};
|
||||
const Expected const_with_error{unexpect, 1337};
|
||||
assert(with_error.error_or(convertible{1}) == 42 + 2);
|
||||
assert(const_with_error.error_or(convertible{1}) == 1337 + 2);
|
||||
static_assert(noexcept(with_error.error_or(convertible{1})) == should_be_noexcept);
|
||||
static_assert(noexcept(const_with_error.error_or(convertible{1})) == should_be_noexcept);
|
||||
|
||||
assert(move(with_error).error_or(convertible{1}) == 42 + 3);
|
||||
assert(move(const_with_error).error_or(convertible{1}) == 1337 + 2);
|
||||
static_assert(noexcept(move(with_error).error_or(convertible{1})) == should_be_noexcept);
|
||||
static_assert(noexcept(move(const_with_error).error_or(convertible{1})) == should_be_noexcept);
|
||||
|
||||
const convertible input{2000};
|
||||
Expected with_value{in_place, 42};
|
||||
const Expected const_with_value{in_place, 1337};
|
||||
assert(with_value.error_or(convertible{1}) == 1 + 5);
|
||||
assert(const_with_value.error_or(input) == 2000 + 4);
|
||||
static_assert(noexcept(with_value.error_or(convertible{1})) == should_be_noexcept);
|
||||
static_assert(noexcept(const_with_value.error_or(input)) == should_be_noexcept);
|
||||
|
||||
assert(move(with_value).error_or(convertible{1}) == 1 + 5);
|
||||
assert(move(const_with_value).error_or(input) == 2000 + 4);
|
||||
static_assert(noexcept(move(with_value).error_or(convertible{1})) == should_be_noexcept);
|
||||
static_assert(noexcept(move(const_with_value).error_or(input)) == should_be_noexcept);
|
||||
}
|
||||
|
||||
{ // test error_or({})
|
||||
using Expected = expected<int, payload_error_or>;
|
||||
|
||||
Expected with_error{unexpect, 42};
|
||||
const Expected const_with_error{unexpect, 1337};
|
||||
Expected with_value{in_place, 42};
|
||||
const Expected const_with_value{in_place, 1337};
|
||||
|
||||
assert(with_error.error_or({}) == 42 + 2);
|
||||
assert(const_with_error.error_or({}) == 1337 + 2);
|
||||
assert(with_value.error_or({}) == 55 + 3);
|
||||
assert(const_with_value.error_or({}) == 55 + 3);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void test_error_or() noexcept {
|
||||
test_error_or<IsNothrowConstructible::Not, IsNothrowConvertible::Not>();
|
||||
test_error_or<IsNothrowConstructible::Not, IsNothrowConvertible::Yes>();
|
||||
test_error_or<IsNothrowConstructible::Yes, IsNothrowConvertible::Not>();
|
||||
test_error_or<IsNothrowConstructible::Yes, IsNothrowConvertible::Yes>();
|
||||
}
|
||||
|
||||
constexpr void test_monadic() {
|
||||
{
|
||||
expected<Thingy, int> engaged{Thingy{11}};
|
||||
expected<Thingy, int> unengaged{unexpect, 22};
|
||||
test_impl(engaged, unengaged);
|
||||
test_impl(as_const(engaged), as_const(unengaged));
|
||||
test_impl(move(engaged), move(unengaged));
|
||||
test_impl(move(as_const(engaged)), move(as_const(unengaged)));
|
||||
}
|
||||
|
||||
{
|
||||
expected<void, int> engaged{};
|
||||
expected<void, int> unengaged{unexpect, 22};
|
||||
test_impl(engaged, unengaged);
|
||||
test_impl(as_const(engaged), as_const(unengaged));
|
||||
test_impl(move(engaged), move(unengaged));
|
||||
test_impl(move(as_const(engaged)), move(as_const(unengaged)));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_error_or();
|
||||
test_monadic();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test();
|
||||
static_assert(test());
|
||||
}
|
|
@ -809,10 +809,10 @@ STATIC_ASSERT(__cpp_lib_execution == 201603L);
|
|||
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
|
||||
#ifndef __cpp_lib_expected
|
||||
#error __cpp_lib_expected is not defined
|
||||
#elif __cpp_lib_expected != 202202L
|
||||
#error __cpp_lib_expected is not 202202L
|
||||
#elif __cpp_lib_expected != 202211L
|
||||
#error __cpp_lib_expected is not 202211L
|
||||
#else
|
||||
STATIC_ASSERT(__cpp_lib_expected == 202202L);
|
||||
STATIC_ASSERT(__cpp_lib_expected == 202211L);
|
||||
#endif
|
||||
#else
|
||||
#ifdef __cpp_lib_expected
|
||||
|
|
Загрузка…
Ссылка в новой задаче