Add const overloads to tuple swap, construction and assignment
Rational of the these tuple changes needed for zip
- Constructor overloads that takes non-const lvalue reference, and const rvalue reference.
Short answer: make zip_view::iterator model indirectly_readable.
Long answer: indirectly_readable requires a common_reference between "lvalue reference to value_type" and reference, in zip's case, this could be tuple<Foo>& (lvalue reference to value_type) and tuple<Foo&> (reference). We need be able to construct tuple<Foo&> from tuple<Foo>&. pre-C++23, the tuple's converting copy constructors takes only const tuple<UTyles...>&. This won't work here because we cannot bind const Foo& to Foo&.
- const member assignment operators
Short answer: make zip_view::iterator model indirectly_writable
Long answer: indirectly_writable requires the type const decltype(*it) to be assignable. The const there is to prevent cases such as sorting a transformed of range of prvalue string. It would have compiled without const because std::string{} = std::string{} is a valid expression. but const std::string{} = std::string{} is not. If the range is a range of references, adding const doesn't do anything. using T = int&, then const T is also int&. So this const in the concept is to ban range of prvalues. However, in zip case, although the reference is prvalue tuple, it is really just a proxy. If we have a tuple of references, we do want to model the concept because the underlying ranges are writable. So we need the const assignment operators if underlying types are const assignable (reference types are const assignable).
- const swap
because of the const assignment operator added above, the default std::swap's triple-move would lead to wrong result for const tuple<Foo&>
Now, here is the summary of the implementations.
- for constructors that takes cvref variation of tuple<UTypes...>, there used to be two SFINAE helper _EnableCopyFromOtherTuple, _EnableMoveFromOtherTuple. And the implementations of these two helpers seem to slightly differ from the spec. But now, we need 4 variations. Instead of adding another two, this change refactored it to a single one _EnableCtrFromUTypesTuple, which directly maps to the spec without changing the C++11 behaviour. However, we need the helper __copy_cvref_t to get the type of std::get<i>(cvref tuple<Utypes...>) for different cvref, so I made __copy_cvref_t to be available in C++11.
- for constructors that takes variations of std::pair, there used to be four helpers _EnableExplicitCopyFromPair, _EnableImplicitCopyFromPair, _EnableImplicitMoveFromPair, _EnableExplicitMoveFromPair. Instead of adding another four, this change refactored into two helper _EnableCtrFromPair and _BothImplicitlyConvertible. This also removes the need to use _nat
- for const member assignment operator, since the requirement is very simple, I haven't refactored the old code but instead directly adding the new c++23 code.
- for const swap, I pretty much copy pasted the non-const version to make these overloads look consistent
- while doing these change, I found two of the old constructors wasn't marked constexpr for C++20 but they should. fixed them and added unit tests
Nit, but let's be consistent. Here and below.