[libcxx-commits] [PATCH] D140911: [libc++] Implement P2505R5(Monadic operations for std::expected)
Hui via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jan 8 14:16:03 PST 2023
huixie90 requested changes to this revision.
huixie90 added a subscriber: jwakely.
huixie90 added a comment.
This revision now requires changes to proceed.
Thank you very much for working on this patch. The implementation looks pretty good to me.
================
Comment at: libcxx/include/__expected/expected.h:68
+
namespace __expected {
----------------
philnik wrote:
> @huixie90 Why do we have this namespace? It doesn't really seem worth it just for `__throw_bad_expected_access`.
The honest answer is i can't remember. perhaps in some point of time I had several functions but got deleted in the end. But it seems that after this patch, there is more stuff in it.
================
Comment at: libcxx/include/__expected/expected.h:625
+ static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
+ return __has_val_ ? static_cast<_Err>(std::forward<_Up>(__v)) : __union_.__unex_;
+ }
----------------
philnik wrote:
> Let's use the public API here to match the wording. You can't `static_cast` here because that might call the wrong function: https://godbolt.org/z/TjPK9YWac. Please add a regression test. Same for the rvalue overload.
IIRC, Eric suggested to use `__has_val_` in place of `has_value()` (and other direct accessor member functions) to reduce the size in debug build
================
Comment at: libcxx/include/__expected/expected.h:94-105
!is_reference_v<_Tp> &&
!is_function_v<_Tp> &&
!is_same_v<remove_cv_t<_Tp>, in_place_t> &&
!is_same_v<remove_cv_t<_Tp>, unexpect_t> &&
!__unexpected::__is_unexpected<remove_cv_t<_Tp>>::value &&
__unexpected::__valid_unexpected<_Err>::value
,
----------------
This section is changed after this paper. Could you please update the `static_assert` and the message?
Please also add tests if there are behaviour changes.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2505r5.html#orgb3c1202
================
Comment at: libcxx/include/__expected/expected.h:184
+ template <class _Func, class... _Args>
+ constexpr explicit expected(
+ __expected::__expected_construct_in_place_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
----------------
_LIBCPP_HIDE_FROM_ABI
================
Comment at: libcxx/include/__expected/expected.h:189
+ template <class _Func, class... _Args>
+ constexpr explicit expected(
+ __expected::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
----------------
_LIBCPP_HIDE_FROM_ABI
================
Comment at: libcxx/include/__expected/expected.h:621
+ template <class _Up = _Err>
+ _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& {
----------------
Could you please add test points for the default template argument? (This applies to other overloads and `expected<void, E>::error_or`)
Without the default template parameter, this syntax would not work.
```
e.error_or({arg});
```
That being said, @jwakely why does `value_or` not have default template argument `class U = T` for consistency?
================
Comment at: libcxx/include/__expected/expected.h:819
+ _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & {
+ using _Up = remove_cv_t<invoke_result_t<_Func, _Err&>>;
+ if (has_value()) {
----------------
It might be better not to call it `_Up` as `U` is usually paired with `T`. But here we are dealing with error type.
I would either stick to the spec to use `_Gp`, or choose some other names like `_OtherErr`. (same for other `transform_error` overloads
================
Comment at: libcxx/include/__expected/expected.h:1036
+ template <class _Func>
+ constexpr explicit expected(__expected::__expected_construct_in_place_from_invoke_tag, _Func&& __f)
+ : __has_val_(true) {
----------------
_LIBCPP_HIDE_FROM_ABI
================
Comment at: libcxx/include/__expected/expected.h:1042
+ template <class _Func, class... _Args>
+ constexpr explicit expected(
+ __expected::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
----------------
_LIBCPP_HIDE_FROM_ABI
================
Comment at: libcxx/include/__expected/expected.h:1214
+ template <class _Up = _Err>
+ _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& {
----------------
same for testing default argument and same comment for the name `_Up`
================
Comment at: libcxx/include/__expected/expected.h:1296-1299
+ static_assert(is_same_v<typename _Up::value_type, _Tp>,
+ "The result of f(error()) must have the same value_type as this expected");
+ if (has_value()) {
+ return _Up();
----------------
optional: perhaps just use `void` instead of `_Tp` to improve the readability? I was slightly confused what `Up()` for a moment and later realised it was a `std::expected<void, E2>` so it can be default constructed
================
Comment at: libcxx/include/__expected/expected.h:1437
+ if (has_value()) {
+ return expected<_Tp, _Up>(in_place);
+ }
----------------
can we make it consistent with other 3 overloads?
================
Comment at: libcxx/test/std/utilities/expected/expected.expected/monadic/and_then.pass.cpp:17
+// template<class F> constexpr auto and_then(F&& f) const &&;
+
+#include <cassert>
----------------
could you please test
> Constraints: is_copy_constructible_v<E> is true.
Usually we have positive and negative `static_assert` to test whether or not the function exists
This applies to all functions with "Constraints"
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D140911/new/
https://reviews.llvm.org/D140911
More information about the libcxx-commits
mailing list