This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3483. `transform_view::iterator`'s difference is overconstrained

Section: 26.7.9.3 [range.transform.iterator], 26.7.22.3 [range.elements.iterator] Status: WP Submitter: Casey Carter Opened: 2020-09-04 Last modified: 2020-11-09

Priority: 0

View all other issues in [range.transform.iterator].

View all issues with WP status.

Discussion:

The difference operation for `transform_view::iterator` is specified in 26.7.9.3 [range.transform.iterator] as:

>     friend constexpr difference_type operator-(const iterator& x, const iterator& y)
>       requires random_access_range<Base>;

> > -22- Effects: Equivalent to: `return x.current_ - y.current_;`

The member `current_` is an iterator of type `iterator_t<Base>`, where `Base` is `V` for `transform_view<V, F>::iterator<false>` and `const V` for `transform_view<V, F>::iterator<true>`. The difference of iterators that appears in the above Effects: element is notably well-defined if their type models `sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>` which `random_access_range<Base>` refines. This overstrong requirement seems to be simply the result of an oversight; it has been present since P0789R0, without — to my recollection — ever having been discussed. We should relax this requirement to provide difference capability for `transform_view`'s iterators whenever the underlying iterators do.

[2020-09-08; Reflector discussion]

During reflector discussions it was observed that `elements_view::iterator` has the same issue and the proposed wording has been extended to cover this template as well.

[2020-09-13; Reflector prioritization]

Set priority to 0 and status to Tentatively Ready after seven votes in favour during reflector discussions.

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4861.

1. Modify 26.7.9.3 [range.transform.iterator] as indicated:

   > >     namespace std::ranges {
   > >       template<input_range V, copy_constructible F>
   > >         requires view<V> && is_object_v<F> &&
   > >                  regular_invocable<F&, range_reference_t<V>> &&
   > >                  can-reference<invoke_result_t<F&, range_reference_t<V>>>
   > >       template<bool Const>
   > >       class transform_view<V, F>::iterator {
   > >       public:
   > >         […]
   > >         friend constexpr iterator operator-(iterator i, difference_type n)
   > >           requires random_access_range<Base>;
   > >         friend constexpr difference_type operator-(const iterator& x, const iterator& y)
   > >           requires random_access_range<Base>sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;
   > >         […]
   > >       };
   > >     }

   > […]

   >     friend constexpr difference_type operator-(const iterator& x, const iterator& y)
   >       requires random_access_range<Base>sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;

   > > -22- Effects: `return x.current_ - y.current_;`

2. Modify 26.7.22.3 [range.elements.iterator] as indicated:

   > >     namespace std::ranges {
   > >       template<input_range V, size_t N>
   > >         requires view<V> && has-tuple-element<range_value_t<V>, N> &&
   > >                  has-tuple-element<remove_reference_t<range_reference_t<V>>, N>
   > >       template<bool Const>
   > >       class elements_view<V, N>::iterator {  // exposition only
   > >         […]
   > >         friend constexpr iterator operator-(iterator x, difference_type y)
   > >           requires random_access_range<Base>;
   > >         friend constexpr difference_type operator-(const iterator& x, const iterator& y)
   > >           requires random_access_range<Base>sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;
   > >       };
   > >     }

   > […]

   >     constexpr difference_type operator-(const iterator& x, const iterator& y)
   >       requires random_access_range<Base>sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;

   > > -21- Effects: `return x.current_ - y.current_;`