iterator_category
when its
difference_type
is not an integer-class type?Section: 25.6.5.3 [range.repeat.iterator], 25.7.33.3 [range.cartesian.iterator] Status: New Submitter: Hewill Kang Opened: 2022-08-27 Last modified: 2023-02-07
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.
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.
Modify 25.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)>; […] }; }
Modify 25.7.33.3 [range.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 autoreferenceoperator[](difference_type n) const requires cartesian-product-is-random-access<Const, First, Vs...>; […] }; }[…]
constexpr autoreferenceoperator[](difference_type n) const requires cartesian-product-is-random-access<Const, First, Vs...>;-24- Effects:
return *((*this) + n);