Implement LWG-3877 Incorrect constraints on `const`-qualified monadic overloads for `std::expected` (#3504)

Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
A. Jiang 2023-03-04 07:20:14 +08:00 коммит произвёл GitHub
Родитель 7155ea6f88
Коммит 882d92ec47
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 158 добавлений и 12 удалений

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

@ -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&>>;
@ -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>>;
@ -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&>>;
@ -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>>;
@ -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)");
@ -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)");
@ -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)");
@ -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. "
@ -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>>;
@ -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>>;
@ -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)");
@ -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)");

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

@ -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());
}