Created on 2024-04-30.00:00:00 last changed 6 months ago
Proposed resolution:
This wording is relative to N4981.
Modify [range.concat.iterator] as indicated:
namespace std::ranges { template<input_range... Views> requires (view<Views> && ...) && (sizeof...(Views) > 0) && concatable<Views...> template<bool Const> class concat_view<Views...>::iterator { public: using iterator_category = see below; // not always present. using iterator_concept = see below; using value_type = concat-value-t<maybe-const<Const, Views>...>; using difference_type = common_type_t<range_difference_t<maybe-const<Const, Views>>...>; private: static constexpr bool concat-is-homogeneous = see below; // exposition only using base-iter = // exposition only variant<iterator_t<maybe-const<Const, Views>>...>; […] friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below) requires concat-is-homogeneous && indirectly_swappable<iterator_t<maybe-const<Const, Views...[0]>>>; friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below) requiressee below(!concat-is-homogeneous) && swappable_with<iter_reference_t<iterator>, iter_reference_t<iterator>> && (... && indirectly_swappable<iterator_t<maybe-const<Const, Views>>>); } […] }-?- concat-is-homogeneous is true if and only if the pack of types iterator_t<maybe-const<Const, Views>>... are all the same.
-1- iterator::iterator_concept is defined as follows: […]friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below) requires concat-is-homogeneous && indirectly_swappable<iterator_t<maybe-const<Const, Views...[0]>>>;-?- Preconditions: x.it_.valueless_by_exception() and y.it_.valueless_by_exception() are each false.
-?- Effects: Equivalent to:std::visit(ranges::iter_swap, x.it_, y.it_);-?- Remarks: The exception specification is equivalent to
noexcept(ranges::iter_swap(std::get<0>(x.it_), std::get<0>(y.it_)))friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below) requiressee below(!concat-is-homogeneous) && swappable_with<iter_reference_t<iterator>, iter_reference_t<iterator>> && (... && indirectly_swappable<iterator_t<maybe-const<Const, Views>>>);-42- Preconditions: x.it_.valueless_by_exception() and y.it_.valueless_by_exception() are each false.
-43- Effects: Equivalent to:std::visit([&](const auto& it1, const auto& it2) { if constexpr (is_same_v<decltype(it1), decltype(it2)>) { ranges::iter_swap(it1, it2); } else { ranges::swap(*x, *y); } }, x.it_, y.it_);-44- Remarks: The exception specification is equivalent to
(noexcept(ranges::swap(*x, *y)) && ... && noexcept(ranges::iter_swap(its, its)))where its is a pack of lvalues of type const iterator_t<maybe-const<Const, Views>> respectively.
The expression in the requires-clause is equivalent toswappable_with<iter_reference_t<iterator>, iter_reference_t<iterator>> && (... && indirectly_swappable<iterator_t<maybe-const<Const, Views>>>)
[ 2024-06-24; Reflector poll ]
Set priority to 3 after reflector poll. An extreme corner case, probably not worth caring about.
When the underlying iterator of two concat_view::iterators are of different types, their iter_swap will dispatch ranges::swap to swap elements, which is reflected in its constraints of swappable_with<iter_reference_t<iterator>, iter_reference_t<iterator>>.
However, when the underlying iterators are all of the same type, ranges::swap will never be invoked, making checking for swappable_with unnecessary in this case. This results in the current wording rejecting the following:
struct I {
using value_type = int;
using difference_type = int;
std::reference_wrapper<int> operator*() const;
I& operator++();
void operator++(int);
bool operator==(const I&) const;
friend void iter_swap(const I&, const I&); // custom iter_swap
};
static_assert(std::indirectly_swappable<I>);
int main() {
std::ranges::subrange<I, I> s1, s2;
std::ranges::swap_ranges(s1, s2);
std::ranges::concat_view c1{s1}, c2{s2};
std::ranges::swap_ranges(c1, c2); // ill-formed
}
Because reference_wrapper does not satisfy swappable_with, concat_view::iterator does not have a valid iter_swap, leading to the constraints of swap_ranges being unsatisfied.
This doesn't seem like it should be, and I think providing a simplified homogeneous iter_swap specialization for concat_view::iterator is reasonable.History | |||
---|---|---|---|
Date | User | Action | Args |
2024-06-24 12:09:57 | admin | set | messages: + msg14185 |
2024-05-04 16:15:51 | admin | set | messages: + msg14102 |
2024-04-30 00:00:00 | admin | create |