Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions stl/inc/expected
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ public:

// [expected.object.monadic]
template <class _Fn>
requires is_copy_constructible_v<_Err>
requires is_constructible_v<_Err, _Err&>
constexpr auto and_then(_Fn&& _Func) & {
using _Uty = remove_cvref_t<invoke_result_t<_Fn, _Ty&>>;

Expand Down Expand Up @@ -789,7 +789,7 @@ public:
}

template <class _Fn>
requires is_move_constructible_v<_Err>
requires is_constructible_v<_Err, const _Err>
constexpr auto and_then(_Fn&& _Func) const&& {
using _Uty = remove_cvref_t<invoke_result_t<_Fn, const _Ty>>;

Expand All @@ -808,7 +808,7 @@ public:
}

template <class _Fn>
requires is_copy_constructible_v<_Ty>
requires is_constructible_v<_Ty, _Ty&>
constexpr auto or_else(_Fn&& _Func) & {
using _Uty = remove_cvref_t<invoke_result_t<_Fn, _Err&>>;

Expand Down Expand Up @@ -865,7 +865,7 @@ public:
}

template <class _Fn>
requires is_move_constructible_v<_Ty>
requires is_constructible_v<_Ty, const _Ty>
constexpr auto or_else(_Fn&& _Func) const&& {
using _Uty = remove_cvref_t<invoke_result_t<_Fn, const _Err>>;

Expand All @@ -884,7 +884,7 @@ public:
}

template <class _Fn>
requires is_copy_constructible_v<_Err>
requires is_constructible_v<_Err, _Err&>
constexpr auto transform(_Fn&& _Func) & {
static_assert(invocable<_Fn, _Ty&>, "expected<T, E>::transform(F) requires that F is invocable with T. "
"(N4928 [expected.object.monadic]/19)");
Expand Down Expand Up @@ -965,7 +965,7 @@ public:
}

template <class _Fn>
requires is_move_constructible_v<_Err>
requires is_constructible_v<_Err, const _Err>
constexpr auto transform(_Fn&& _Func) const&& {
static_assert(invocable<_Fn, const _Ty>, "expected<T, E>::transform(F) requires that F is invocable with T. "
"(N4928 [expected.object.monadic]/23)");
Expand All @@ -992,7 +992,7 @@ public:
}

template <class _Fn>
requires is_copy_constructible_v<_Ty>
requires is_constructible_v<_Ty, _Ty&>
constexpr auto transform_error(_Fn&& _Func) & {
static_assert(invocable<_Fn, _Err&>, "expected<T, E>::transform_error(F) requires that F is invocable with E. "
"(N4928 [expected.object.monadic]/27)");
Expand Down Expand Up @@ -1053,7 +1053,7 @@ public:
}

template <class _Fn>
requires is_move_constructible_v<_Ty>
requires is_constructible_v<_Ty, const _Ty>
constexpr auto transform_error(_Fn&& _Func) const&& {
static_assert(invocable<_Fn, const _Err>,
"expected<T, E>::transform_error(F) requires that F is invocable with E. "
Expand Down Expand Up @@ -1470,7 +1470,7 @@ public:

// [expected.void.monadic]
template <class _Fn>
requires is_copy_constructible_v<_Err>
requires is_constructible_v<_Err, _Err&>
constexpr auto and_then(_Fn&& _Func) & {
using _Uty = remove_cvref_t<invoke_result_t<_Fn>>;

Expand Down Expand Up @@ -1527,7 +1527,7 @@ public:
}

template <class _Fn>
requires is_move_constructible_v<_Err>
requires is_constructible_v<_Err, const _Err>
constexpr auto and_then(_Fn&& _Func) const&& {
using _Uty = remove_cvref_t<invoke_result_t<_Fn>>;

Expand Down Expand Up @@ -1618,7 +1618,7 @@ public:
}

template <class _Fn>
requires is_copy_constructible_v<_Err>
requires is_constructible_v<_Err, _Err&>
constexpr auto transform(_Fn&& _Func) & {
static_assert(invocable<_Fn>, "expected<void, E>::transform(F) requires that F is invocable with no arguments. "
"(N4928 [expected.void.monadic]/17)");
Expand Down Expand Up @@ -1696,7 +1696,7 @@ public:
}

template <class _Fn>
requires is_move_constructible_v<_Err>
requires is_constructible_v<_Err, const _Err>
constexpr auto transform(_Fn&& _Func) const&& {
static_assert(invocable<_Fn>, "expected<void, E>::transform(F) requires that F is invocable with no arguments. "
"(N4928 [expected.void.monadic]/21)");
Expand Down
146 changes: 146 additions & 0 deletions tests/std/tests/P2505R5_monadic_functions_for_std_expected/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,153 @@ constexpr bool test() {
return true;
}

template <class T, template <class...> class Tmpl>
constexpr bool is_specialization_of = false;

template <template <class...> class Tmpl, class... Args>
constexpr bool is_specialization_of<Tmpl<Args...>, Tmpl> = true;

template <class T>
requires is_specialization_of<remove_cvref_t<T>, expected>
using expected_value_t = typename remove_cvref_t<T>::value_type;

template <class T>
requires is_specialization_of<remove_cvref_t<T>, expected>
using expected_error_t = typename remove_cvref_t<T>::error_type;

template <class R>
struct DefaultTransformer {
constexpr R operator()() const {
return R();
}

constexpr R operator()(auto&&) const {
return R();
}
};

template <class T>
concept CanAndThen =
is_specialization_of<remove_cvref_t<T>, expected>
&& requires(T&& t) { forward<T>(t).and_then(DefaultTransformer<expected<void, expected_error_t<T>>>{}); };

template <class T>
concept CanOrElse =
is_specialization_of<remove_cvref_t<T>, expected>
&& requires(T&& t) { forward<T>(t).or_else(DefaultTransformer<expected<expected_value_t<T>, char>>{}); };

template <class T>
concept CanTransform = is_specialization_of<remove_cvref_t<T>, expected>
&& requires(T&& t) { forward<T>(t).transform(DefaultTransformer<expected_value_t<T>>{}); };

template <class T>
concept CanTransformError =
is_specialization_of<remove_cvref_t<T>, expected>
&& requires(T&& t) { forward<T>(t).transform_error(DefaultTransformer<expected_error_t<T>>{}); };

enum class HasMutCopy : bool { No, Yes };

enum class HasConstCopy : bool { No, Yes };

enum class HasMutMove : bool { No, Yes };

enum class HasConstMove : bool { No, Yes };

template <HasMutCopy MutCopyStatus, HasConstCopy ConstCopyStatus, HasMutMove MutMoveStatus,
HasConstMove ConstMoveStatus>
struct State {
State() = default;
// clang-format off
State(State&) requires (static_cast<bool>(MutCopyStatus)) = default;
State(State&) requires (!static_cast<bool>(MutCopyStatus)) = delete;
State(const State&) requires (static_cast<bool>(ConstCopyStatus)) = default;
State(const State&) requires (!static_cast<bool>(ConstCopyStatus)) = delete;
State(State&&) requires (static_cast<bool>(MutMoveStatus)) = default;
State(State&&) requires (!static_cast<bool>(MutMoveStatus)) = delete;
State(const State&&) requires (!static_cast<bool>(ConstMoveStatus)) = delete;
// clang-format on

template <class U = State>
requires (!static_cast<bool>(ConstCopyStatus) && static_cast<bool>(ConstMoveStatus))
constexpr State(const type_identity_t<U>&&) noexcept {}

State& operator=(const State&) = default;
State& operator=(State&&) = default;
};

template <int N>
constexpr bool test_monadic_constraints_impl() {
constexpr bool MutCopyStatus = static_cast<bool>(N & 0b0001);
constexpr bool ConstCopyStatus = static_cast<bool>(N & 0b0010);
constexpr bool MutMoveStatus = static_cast<bool>(N & 0b0100);
constexpr bool ConstMoveStatus = static_cast<bool>(N & 0b1000);

using T = State<static_cast<HasMutCopy>(MutCopyStatus), static_cast<HasConstCopy>(ConstCopyStatus),
static_cast<HasMutMove>(MutMoveStatus), static_cast<HasConstMove>(ConstMoveStatus)>;

static_assert(is_constructible_v<T, T&> == MutCopyStatus);
static_assert(is_constructible_v<T, const T&> == ConstCopyStatus);
static_assert(is_constructible_v<T, T> == MutMoveStatus);
static_assert(is_constructible_v<T, const T> == ConstMoveStatus);

static_assert(CanAndThen<expected<int, T>&> == MutCopyStatus || ConstCopyStatus);
static_assert(CanAndThen<const expected<int, T>&> == ConstCopyStatus);
static_assert(CanAndThen<expected<int, T>> == MutMoveStatus || ConstCopyStatus || ConstMoveStatus);
static_assert(CanAndThen<const expected<int, T>> == ConstMoveStatus || ConstCopyStatus);

static_assert(CanAndThen<expected<void, T>&> == MutCopyStatus || ConstCopyStatus);
static_assert(CanAndThen<const expected<void, T>&> == ConstCopyStatus);
static_assert(CanAndThen<expected<void, T>> == MutMoveStatus || ConstCopyStatus || ConstMoveStatus);
static_assert(CanAndThen<const expected<void, T>> == ConstMoveStatus || ConstCopyStatus);

static_assert(CanOrElse<expected<T, char>&> == MutCopyStatus || ConstCopyStatus);
static_assert(CanOrElse<const expected<T, char>&> == ConstCopyStatus);
static_assert(CanOrElse<expected<T, char>> == MutMoveStatus || ConstCopyStatus || ConstMoveStatus);
static_assert(CanOrElse<const expected<T, char>> == ConstMoveStatus || ConstCopyStatus);

static_assert(CanTransform<expected<int, T>&> == MutCopyStatus || ConstCopyStatus);
static_assert(CanTransform<const expected<int, T>&> == ConstCopyStatus);
static_assert(CanTransform<expected<int, T>> == MutMoveStatus || ConstCopyStatus || ConstMoveStatus);
static_assert(CanTransform<const expected<int, T>> == ConstMoveStatus || ConstCopyStatus);

static_assert(CanTransform<expected<void, T>&> == MutCopyStatus || ConstCopyStatus);
static_assert(CanTransform<const expected<void, T>&> == ConstCopyStatus);
static_assert(CanTransform<expected<void, T>> == MutMoveStatus || ConstCopyStatus || ConstMoveStatus);
static_assert(CanTransform<const expected<void, T>> == ConstMoveStatus || ConstCopyStatus);

static_assert(CanTransformError<expected<T, char>&> == MutCopyStatus || ConstCopyStatus);
static_assert(CanTransformError<const expected<T, char>&> == ConstCopyStatus);
static_assert(CanTransformError<expected<T, char>> == MutMoveStatus || ConstCopyStatus || ConstMoveStatus);
static_assert(CanTransformError<const expected<T, char>> == ConstMoveStatus || ConstCopyStatus);

return true;
}

constexpr bool test_monadic_constraints() {
static_assert(test_monadic_constraints_impl<0b0000>());
static_assert(test_monadic_constraints_impl<0b0001>());
static_assert(test_monadic_constraints_impl<0b0010>());
static_assert(test_monadic_constraints_impl<0b0011>());
static_assert(test_monadic_constraints_impl<0b0100>());
static_assert(test_monadic_constraints_impl<0b0101>());
static_assert(test_monadic_constraints_impl<0b0110>());
static_assert(test_monadic_constraints_impl<0b0111>());
static_assert(test_monadic_constraints_impl<0b1000>());
static_assert(test_monadic_constraints_impl<0b1001>());
static_assert(test_monadic_constraints_impl<0b1010>());
static_assert(test_monadic_constraints_impl<0b1011>());
static_assert(test_monadic_constraints_impl<0b1100>());
static_assert(test_monadic_constraints_impl<0b1101>());
static_assert(test_monadic_constraints_impl<0b1110>());
static_assert(test_monadic_constraints_impl<0b1111>());

return true;
}

int main() {
test();
static_assert(test());

assert(test_monadic_constraints());
static_assert(test_monadic_constraints());
}