Created on 2023-01-06.00:00:00 last changed 22 months ago
Proposed resolution:
This wording is relative to N4917.
Modify [range.join.with.iterator] as indicated:
[…]namespace std::ranges { template<input_range V, forward_range Pattern> requires view<V> && input_range<range_reference_t<V>> && view<Pattern> && compatible-joinable-ranges<range_reference_t<V>, Pattern> template<bool Const> class join_with_view<V, Pattern>::iterator { […] Parent* parent_ = nullptr; // exposition only OuterIter outer_it_ = OuterIter(); // exposition only variant<PatternIter, InnerIter> inner_it_; // exposition only […] public: […] friend constexpr decltype(auto) iter_move(const iterator& x) noexcept(see below);{ using rvalue_reference = common_reference_t< iter_rvalue_reference_t<InnerIter>, iter_rvalue_reference_t<PatternIter>>; return visit<rvalue_reference>(ranges::iter_move, x.inner_it_); }friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below) requires indirectly_swappable<InnerIter, PatternIter>;{ visit(ranges::iter_swap, x.inner_it_, y.inner_it_); }}; }friend constexpr decltype(auto) iter_move(const iterator& x) noexcept(see below);-?- Let rvalue_reference be:
common_reference_t<iter_rvalue_reference_t<InnerIter>, iter_rvalue_reference_t<PatternIter>>-?- Preconditions: x.inner_it_.valueless_by_exception() is false.
-?- Effects: Equivalent to: return visit<rvalue_reference>(ranges::iter_move, x.inner_it_);
-?- Remarks: The exception specification is equivalent to:
noexcept(ranges::iter_move(declval<const InnerIter&>())) && noexcept(ranges::iter_move(declval<const PatternIter&>())) && is_nothrow_convertible_v<iter_rvalue_reference_t<InnerIter>, rvalue_reference> && is_nothrow_convertible_v<iter_rvalue_reference_t<PatternIter>, rvalue_reference>friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below) requires indirectly_swappable<InnerIter, PatternIter>;-?- Preconditions: x.inner_it_.valueless_by_exception() and y.inner_it_.valueless_by_exception() are each false.
-?- Effects: Equivalent to: visit(ranges::iter_swap, x.inner_it_, y.inner_it_).
-?- Remarks: The exception specification is equivalent to:
noexcept(ranges::iter_swap(declval<const InnerIter&>(), declval<const InnerIter&>())) && noexcept(ranges::iter_swap(declval<const PatternIter&>(), declval<const PatternIter&>()))
[ 2023-02-01; Reflector poll ]
Set priority to 3 after reflector poll. "The iter_swap specification is wrong since we can swap Pattern and Inner. And this is something implementations can strengthen."
In order to preserve room for optimization, the standard always tries to propagate the noexcept specification of custom iter_move/iter_swap for different iterators.
But for join_with_view::iterator, these two specializations are the only ones in the standard that do not have a noexcept specification. This is because both invoke visit in the function body, and visit may throw an exception when the variant does not hold a value.
However, implementors are not required to follow the standard practice. Since the join_with_view::iterator's variant member only contains two alternative types, both libstdc++ and MSVC-STL avoid heavyweight visit calls by simply using multiple if statements. This means that it is still possible to add a conditional noexcept specification to these overloads, and there is already a precedent in the standard, namely common_iterator. All we need to do is add a Preconditions.
History | |||
---|---|---|---|
Date | User | Action | Args |
2023-02-01 20:48:23 | admin | set | messages: + msg13250 |
2023-01-06 16:24:01 | admin | set | messages: + msg13191 |
2023-01-06 00:00:00 | admin | create |