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

### 3763. Should range adaptor iterators only provide `iterator_category` when its `difference_type` is not an integer-class type?

Section: 26.6.5.3 [range.repeat.iterator], 26.7.31.3 [ranges.cartesian.iterator] Status: New Submitter: Hewill Kang Opened: 2022-08-27 Last modified: 2022-09-23

Priority: 3

View all issues with New status.

Discussion:

After P2259, the range adaptor' iterators only provide `iterator_category` member when the underlying range models `forward_range`, which is mainly based on the premise that all valid C++20 forward iterators meet the C++17 input iterator requirements.

However, this is not strictly correct. When the underlying range's `difference_type` is an integer-class type, its iterator does not conform Cpp17InputIterator.

Although `iterator_traits<I>::iterator_category` will still deduce the correct category in this case since these iterators have no `reference` member, it might be misleading to provide these incorrect member types.

Do we need to aggressively prohibit these iterators from providing `iterator_category` when their difference type is an integer-class type?

The proposed resolution makes `repeat_view::iterator` conditionally provide `iterator_category`, because it explicitly mentions `IOTA-DIFF-T(index-type)` in the definition of `difference_type`, which makes it consistent with LWG 3670.

It also removes the `reference` member type of `cartesian_product_view::iterator`, which prevents `iterator_traits<I>::iterator_category` from being aliased to its member `iterator_category`, so that `iterator_traits<I>::iterator_category` will not always be an `input_iterator_tag` when its `difference_type` is an integer-class type.

This is also consistent with other range adaptors, as none of them have a `reference` member type.

[2022-09-23; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4917.

1. Modify 26.6.5.3 [range.repeat.iterator] as indicated:

   >     namespace std::ranges {
   >       template<move_constructible W, semiregular Bound = unreachable_sentinel_t>
   >         requires (is_object_v<W> && same_as<W, remove_cv_t<W>> &&
   >                   (is-integer-like<Bound> || same_as<Bound, unreachable_sentinel_t>))
   >       class repeat_view<W, Bound>::iterator {
   >       private:
   >         using index-type =                  // exposition only
   >           conditional_t<same_as<Bound, unreachable_sentinel_t>, ptrdiff_t, Bound>;
   >         const W* value_ = nullptr;          // exposition only
   >         index-type current_ = index-type(); // exposition only

   >         constexpr explicit iterator(const W* value, index-type b = index-type());   // exposition only

   >       public:
   >         using iterator_concept = random_access_iterator_tag;
   >         using iterator_category = random_access_iterator_tag;           // present only if difference_type
   >                                                                         // is an integral type
   >         using value_type = W;
   >         using difference_type = conditional_t<is-signed-integer-like<index-type>,
   >             index-type,
   >             IOTA-DIFF-T(index-type)>;
   >         […]
   >       };
   >     }

2. Modify 26.7.31.3 [ranges.cartesian.iterator] as indicated:

   > >     namespace std::ranges {
   > >       template<input_range First, forward_range... Vs>
   > >         requires (view<First> && ... && view<Vs>)
   > >       template<bool Const>
   > >       class cartesian_product_view<First, Vs...>::iterator {
   > >       public:
   > >         using iterator_category = input_iterator_tag;
   > >         using iterator_concept  = see below;
   > >         using value_type = tuple<range_value_t<maybe-const<Const, First>>,
   > >           range_value_t<maybe-const<Const, Vs>>...>;
   > >         using reference = tuple<range_reference_t<maybe-const<Const, First>>,
   > >           range_reference_t<maybe-const<Const, Vs>>...>;
   > >         using difference_type = see below;
   > >         […]

   > >         constexpr autoreference operator[](difference_type n) const
   > >           requires cartesian-product-is-random-access<Const, First, Vs...>;

   > >         […]
   > >       };
   > >     }

   > […]

   >     constexpr autoreference operator[](difference_type n) const
   >       requires cartesian-product-is-random-access<Const, First, Vs...>;

   > > -24- Effects: `return *((*this) + n);`