join_view::iterator::iterator_category and ::iterator_concept lieSection: 25.7.14.3 [range.join.iterator] Status: C++23 Submitter: Casey Carter Opened: 2021-03-16 Last modified: 2023-11-22
Priority: 2
View all other issues in [range.join.iterator].
View all issues with C++23 status.
Discussion:
Per 25.7.14.3 [range.join.iterator]/1, join_view::iterator::iterator_concept denotes
bidirectional_iterator_tag if ref-is-glvalue is true and Base and
range_reference_t<Base> each model bidirectional_range. Similarly, paragraph 2 says that
join_view::iterator::iterator_category is present if ref-is-glvalue is true,
and denotes bidirectional_iterator_tag if the categories of the iterators of both Base and
range_reference_t<Base> derive from bidirectional_iterator_tag.
operator-- and operator--(int) in the synopsis
that immediately precedes paragraph 1 disagree. Certainly they also consistently require ref-is-glvalue
&& bidirectional_range<Base> && bidirectional_range<range_reference_t<Base>>,
but they additionally require common_range<range_reference_t<Base>>. So as currently specified,
this iterator sometimes declares itself to be bidirectional despite not implementing --. This is not
incorrect for iterator_concept — recall that iterator_concept is effectively an upper bound since
the concepts require substantial syntax — but slightly misleading. It is, however, very much incorrect for
iterator_category which must not denote a type derived from a tag that corresponds to a stronger category
than that iterator implements.
It's worth pointing out, that LWG 3313 fixed the constraints on operator--() and
operator--(int) by adding the common_range requirements, but failed to make a consistent change
to the definitions of iterator_concept and iterator_category.
[2021-04-04; Daniel comments]
The below proposed wording can be compared as being based on N4885.
[2021-04-20; Reflector poll]
Priority set to 2.
[2021-06-23; Reflector poll]
Set status to Tentatively Ready after six votes in favour during reflector poll.
[2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to the post-2021-February-virtual-meeting working draft.
Modify 25.7.14.3 [range.join.iterator] as indicated:
-1-
iterator::iterator_conceptis defined as follows:
(1.1) — If
ref-is-glvalueistrue,andBaseandmodelsrange_reference_t<Base>eachbidirectional_range, andrange_reference_t<Base>models bothbidirectional_rangeandcommon_range, theniterator_conceptdenotesbidirectional_iterator_tag.[…]
[…]
-2- The member typedef-nameiterator_categoryis defined if and only ifref-is-glvalueistrue,Basemodelsforward_range, andrange_reference_t<Base>modelsforward_range. In that case,iterator::iterator_categoryis defined as follows:
(2.1) — Let
OUTERCdenoteiterator_traits<iterator_t<Base>>::iterator_category, and letINNERCdenoteiterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category.(2.2) — If
OUTERCandINNERCeach modelderived_from<bidirectional_iterator_tag>, andrange_reference_t<Base>modelscommon_range,iterator_categorydenotesbidirectional_iterator_tag.[…]