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:
Sy Brand 2023-02-10 23:10:35 +00:00 коммит произвёл GitHub
Родитель 1abaa14ee5
Коммит 8f912858db
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 1208 добавлений и 40 удалений

Просмотреть файл

@ -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