[libcxx-commits] [PATCH] D116621: [libc++][P2321R2] Add const overloads to tuple swap, construction and assignment
Arthur O'Dwyer via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jan 30 18:09:28 PST 2022
Quuxplusone added inline comments.
================
Comment at: libcxx/include/tuple:215
+}
+#endif
+
----------------
Please use `__x` and `__y` for consistency with lines 201–207.
Separately, don't you need a `noexcept`-spec similar to line 204?
================
Comment at: libcxx/include/tuple:307
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ int swap(const __tuple_leaf& __rhs) const noexcept(is_nothrow_swappable_v<__tuple_leaf>) {
+ _VSTD::swap(*this, __rhs);
----------------
jloser wrote:
> No action required, but it looks slightly odd that this uses `noexcept` directly whereas the one above uses `_NOEXCEPT_` . Ditto for the new `swap` implemented below.
I suspect this (and lines 381 and 479) should be `noexcept(is_nothrow_swappable_v<const __tuple_leaf&>)`. If I'm right, you should be able to (and thus, should) write a regression test that detects this mistake by smacking into the noexcept and `std::terminate`'ing when in fact it shouldn't.
Here and line 380, please be consistent: either return `int` in both places for consistency with lines 299 and 373, or return `void` in both places because we can. (Ah, but if you return `void` then you'll have to use a fold-expression on line 480 instead of a `__swallow`. So return `int` for consistency.)
================
Comment at: libcxx/include/tuple:479
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ void swap(const __tuple_impl& __rhs) const noexcept(__all<is_nothrow_swappable_v<_Tp>...>::value) {
+ _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast<const __tuple_leaf<_Indx, _Tp>&>(__rhs))...);
----------------
Since this is C++17-or-later, you can use `noexcept((is_nothrow_swappable_v<const _Tp&> && ...))`
================
Comment at: libcxx/include/tuple:746-749
+ template <class... _Up, __enable_if_t< requires {
+ sizeof...(_Up) == sizeof...(_Tp);
+ _EnableCopyFromOtherTuple<_Up...>::value;
+ }, int> = 0>
----------------
(1) Can't use `requires` because of `_LIBCPP_HAS_NO_CONCEPTS`.
(2) Don't want to use `requires` because what you actually meant is `sizeof...(_Up) == sizeof...(_Tp)` should be //true//, not just well-formed. I'd go so far as to claim that in libc++ contexts, mixing `enable_if_t` with `requires` is always wrong. (But maybe that's trivially true because if you were able to use `requires` you wouldn't need `enable_if_t` to express a constraint.)
(3) `__enable_if_t<sizeof...(_Up) == sizeof...(_Tp) && _EnableCopyFromOtherTuple<_Up...>::value>* = nullptr`
================
Comment at: libcxx/include/tuple:761
+ tuple(allocator_arg_t, const _Alloc& __alloc, tuple<_Up...>& __t) : __base_(allocator_arg_t(), __alloc, __t) {}
+#endif
+
----------------
Bikeshed: should `explicit(...)` be indented on lines 751 and 759? Personally I think not. It's not a "subordinate" clause in any sense; we don't normally indent the return type or `constexpr` when //that's// on a line by itself.
Significant: I assume you mean `explicit(!(...))`, right? Haven't checked the wording, but I would guess we want the ctor to be //implicit// only if all the types are convertible, not //explicit//. Please add a regression test for each of these `explicit`s; you can check by temporarily removing the `!` from one at a time, and making sure that some test fails, for each of them.
================
Comment at: libcxx/include/tuple:835
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ explicit((is_convertible_v<const _Up&, _Tp> && ...))
+ tuple(const tuple<_Up...>&& __t) : __base_(_VSTD::move(__t)) {}
----------------
`&` should presumably be `&&`; please add a regression test.
================
Comment at: libcxx/include/tuple:968-985
+ template <class _Up1, class _Up2, class... _DependentTp>
+ struct _EnableMoveFromPair : _And<
is_constructible<_FirstType<_DependentTp...>, _Up1>,
is_constructible<_SecondType<_DependentTp...>, _Up2>,
- is_convertible<_Up1, _FirstType<_DependentTp...> >, // explicit check
is_convertible<_Up2, _SecondType<_DependentTp...> >
+ > {};
+
----------------
Again I haven't checked the wording (just cppreference), but this feels convoluted and thus wrong. It should be more like:
- EnableImplicitMoveFromPair if both types are implicitly convertible
- EnableExplicitMoveFromPair if both types are explicitly constructible //and not EnableImplicitMoveFromPair//
Which I think is how it was.
The only thing C++23 changes, AFAIK, is that now we've got two more ctors taking `pair&` and `const pair&&` in addition to C++11's `const pair&` and `pair&&`.
Actually I think your way of doing it below (lines 987-1012) is fine, except that you're misusing `requires` again — and you probably need to `#if _LIBCPP_STD_VER <= 20` the existing ctors from pair, so that in C++23 we get //only// the new conditionally-explicit four below.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D116621/new/
https://reviews.llvm.org/D116621
More information about the libcxx-commits
mailing list