9 Iterators library [iterators]

9.7 Iterator adaptors [iterators.predef]

9.7.6 Counted iterators [iterators.counted]

9.7.6.1 Class template counted_iterator [counted.iterator]

Class template counted_iterator is an iterator adaptor with the same behavior as the underlying iterator except that it keeps track of its distance from its starting position. It can be used together with class default_sentinel in calls to generic algorithms to operate on a range of N elements starting at a given position without needing to know the end position a priori.

Example:

list<string> s;
// populate the list s with at least 10 strings
vector<string> v(make_counted_iterator(s.begin(), 10),
                 default_sentinel()); // copies 10 strings into v

 — end example ]

Two values i1 and i2 of (possibly differing) types counted_iterator<I1> and counted_iterator<I2> refer to elements of the same sequence if and only if next(i1.base(), i1.count()) and next(i2.base(), i2.count()) refer to the same (possibly past-the-end) element.

namespace std { namespace experimental { namespace ranges { inline namespace v1 {
  template <Iterator I>
  class counted_iterator {
  public:
    using iterator_type = I;
    using difference_type = difference_type_t<I>;

    constexpr counted_iterator();
    constexpr counted_iterator(I x, difference_type_t<I> n);
    constexpr counted_iterator(const counted_iterator<ConvertibleTo<I>>& i);
    constexpr counted_iterator& operator=(const counted_iterator<ConvertibleTo<I>>& i);

    constexpr I base() const;
    constexpr difference_type_t<I> count() const;
    constexpr decltype(auto) operator*();
    constexpr decltype(auto) operator*() const
      requires dereferenceable<const I>;

    constexpr counted_iterator& operator++();
    decltype(auto) operator++(int);
    constexpr counted_iterator operator++(int)
      requires ForwardIterator<I>;
    constexpr counted_iterator& operator--()
      requires BidirectionalIterator<I>;
    constexpr counted_iterator operator--(int)
      requires BidirectionalIterator<I>;

    constexpr counted_iterator  operator+ (difference_type n) const
      requires RandomAccessIterator<I>;
    constexpr counted_iterator& operator+=(difference_type n)
      requires RandomAccessIterator<I>;
    constexpr counted_iterator  operator- (difference_type n) const
      requires RandomAccessIterator<I>;
    constexpr counted_iterator& operator-=(difference_type n)
      requires RandomAccessIterator<I>;
    constexpr decltype(auto) operator[](difference_type n) const
      requires RandomAccessIterator<I>;

    friend constexpr rvalue_reference_t<I> iter_move(const counted_iterator& i)
      noexcept(see below)
        requires InputIterator<I>;
    template <IndirectlySwappable<I> I2>
      friend constexpr void iter_swap(const counted_iterator& x, const counted_iterator<I2>& y)
        noexcept(see below);

  private:
    I current; // exposition only
    difference_type_t<I> cnt; // exposition only
  };

  template <Readable I>
  struct value_type<counted_iterator<I>> {
    using type = value_type_t<I>;
  };

  template <InputIterator I>
  struct iterator_category<counted_iterator<I>> {
    using type = iterator_category_t<I>;
  };

  template <class I1, class I2>
      requires Common<I1, I2>
    constexpr bool operator==(
      const counted_iterator<I1>& x, const counted_iterator<I2>& y);
    constexpr bool operator==(
      const counted_iterator<auto>& x, default_sentinel);
    constexpr bool operator==(
      default_sentinel, const counted_iterator<auto>& x);

  template <class I1, class I2>
      requires Common<I1, I2>
    constexpr bool operator!=(
      const counted_iterator<I1>& x, const counted_iterator<I2>& y);
    constexpr bool operator!=(
      const counted_iterator<auto>& x, default_sentinel y);
    constexpr bool operator!=(
      default_sentinel x, const counted_iterator<auto>& y);

  template <class I1, class I2>
      requires Common<I1, I2>
    constexpr bool operator<(
      const counted_iterator<I1>& x, const counted_iterator<I2>& y);
  template <class I1, class I2>
      requires Common<I1, I2>
    constexpr bool operator<=(
      const counted_iterator<I1>& x, const counted_iterator<I2>& y);
  template <class I1, class I2>
      requires Common<I1, I2>
    constexpr bool operator>(
      const counted_iterator<I1>& x, const counted_iterator<I2>& y);
  template <class I1, class I2>
      requires Common<I1, I2>
    constexpr bool operator>=(
      const counted_iterator<I1>& x, const counted_iterator<I2>& y);
  template <class I1, class I2>
      requires Common<I1, I2>
    constexpr difference_type_t<I2> operator-(
      const counted_iterator<I1>& x, const counted_iterator<I2>& y);
  template <class I>
    constexpr difference_type_t<I> operator-(
      const counted_iterator<I>& x, default_sentinel y);
  template <class I>
    constexpr difference_type_t<I> operator-(
      default_sentinel x, const counted_iterator<I>& y);

  template <RandomAccessIterator I>
    constexpr counted_iterator<I> operator+(
      difference_type_t<I> n, const counted_iterator<I>& x);

  template <Iterator I>
    constexpr counted_iterator<I> make_counted_iterator(I i, difference_type_t<I> n);
}}}}

9.7.6.2 counted_iterator operations [counted.iter.ops]

9.7.6.2.1 counted_iterator constructors [counted.iter.op.const]

constexpr counted_iterator();

Effects: Constructs a counted_iterator, value-initializing current and cnt. Iterator operations applied to the resulting iterator have defined behavior if and only if the corresponding operations are defined on a value-initialized iterator of type I.

constexpr counted_iterator(I i, difference_type_t<I> n);

Requires: n >= 0

Effects: Constructs a counted_iterator, initializing current with i and cnt with n.

constexpr counted_iterator(const counted_iterator<ConvertibleTo<I>>& i);

Effects: Constructs a counted_iterator, initializing current with i.current and cnt with i.cnt.

9.7.6.2.2 counted_iterator::operator= [counted.iter.op=]

constexpr counted_iterator& operator=(const counted_iterator<ConvertibleTo<I>>& i);

Effects: Assigns i.current to current and i.cnt to cnt.

9.7.6.2.3 counted_iterator conversion [counted.iter.op.conv]

constexpr I base() const;

Returns: current.

9.7.6.2.4 counted_iterator count [counted.iter.op.cnt]

constexpr difference_type_t<I> count() const;

Returns: cnt.

9.7.6.2.5 counted_iterator::operator* [counted.iter.op.star]

constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const requires dereferenceable<const I>;

Effects: Equivalent to: return *current;

9.7.6.2.6 counted_iterator::operator++ [counted.iter.op.incr]

constexpr counted_iterator& operator++();

Requires: cnt > 0

Effects: Equivalent to:

++current;
--cnt;

Returns: *this.

decltype(auto) operator++(int);

Requires: cnt > 0.

Effects: Equivalent to:

--cnt;
try { return current++; }
catch(...) { ++cnt; throw; }

constexpr counted_iterator operator++(int) requires ForwardIterator<I>;

Requires: cnt > 0

Effects: Equivalent to:

counted_iterator tmp = *this;
++*this;
return tmp;

9.7.6.2.7 counted_iterator::operator-- [counted.iter.op.decr]

constexpr counted_iterator& operator--(); requires BidirectionalIterator<I>

Effects: Equivalent to:

--current;
++cnt;

Returns: *this.

constexpr counted_iterator operator--(int) requires BidirectionalIterator<I>;

Effects: Equivalent to:

counted_iterator tmp = *this;
--*this;
return tmp;

9.7.6.2.8 counted_iterator::operator+ [counted.iter.op.+]

constexpr counted_iterator operator+(difference_type n) const requires RandomAccessIterator<I>;

Requires: n <= cnt

Effects: Equivalent to: return counted_iterator(current + n, cnt - n);

9.7.6.2.9 counted_iterator::operator+= [counted.iter.op.+=]

constexpr counted_iterator& operator+=(difference_type n) requires RandomAccessIterator<I>;

Requires: n <= cnt

Effects:

current += n;
cnt -= n;

Returns: *this.

9.7.6.2.10 counted_iterator::operator- [counted.iter.op.-]

constexpr counted_iterator operator-(difference_type n) const requires RandomAccessIterator<I>;

Requires: -n <= cnt

Effects: Equivalent to: return counted_iterator(current - n, cnt + n);

9.7.6.2.11 counted_iterator::operator-= [counted.iter.op.-=]

constexpr counted_iterator& operator-=(difference_type n) requires RandomAccessIterator<I>;

Requires: -n <= cnt

Effects:

current -= n;
cnt += n;

Returns: *this.

9.7.6.2.12 counted_iterator::operator[] [counted.iter.op.index]

constexpr decltype(auto) operator[](difference_type n) const requires RandomAccessIterator<I>;

Requires: n <= cnt

Effects: Equivalent to: return current[n];

9.7.6.2.13 counted_iterator comparisons [counted.iter.op.comp]

template <class I1, class I2> requires Common<I1, I2> constexpr bool operator==( const counted_iterator<I1>& x, const counted_iterator<I2>& y);

Requires: x and y shall refer to elements of the same sequence ([iterators.counted]).

Effects: Equivalent to: return x.cnt == y.cnt;

constexpr bool operator==( const counted_iterator<auto>& x, default_sentinel); constexpr bool operator==( default_sentinel, const counted_iterator<auto>& x);

Effects: Equivalent to: return x.cnt == 0;

template <class I1, class I2> requires Common<I1, I2> constexpr bool operator!=( const counted_iterator<I1>& x, const counted_iterator<I2>& y); constexpr bool operator!=( const counted_iterator<auto>& x, default_sentinel); constexpr bool operator!=( default_sentinel, const counted_iterator<auto>& x);

Requires: For the first overload, x and y shall refer to elements of the same sequence ([iterators.counted]).

Effects: Equivalent to: return !(x == y);

template <class I1, class I2> requires Common<I1, I2> constexpr bool operator<( const counted_iterator<I1>& x, const counted_iterator<I2>& y);

Requires: x and y shall refer to elements of the same sequence ([iterators.counted]).

Effects: Equivalent to: return y.cnt < x.cnt;

Note: The argument order in the Effects element is reversed because cnt counts down, not up.  — end note ]

template <class I1, class I2> requires Common<I1, I2> constexpr bool operator<=( const counted_iterator<I1>& x, const counted_iterator<I2>& y);

Requires: x and y shall refer to elements of the same sequence ([iterators.counted]).

Effects: Equivalent to: return !(y < x);

template <class I1, class I2> requires Common<I1, I2> constexpr bool operator>( const counted_iterator<I1>& x, const counted_iterator<I2>& y);

Requires: x and y shall refer to elements of the same sequence ([iterators.counted]).

Effects: Equivalent to: return y < x;

template <class I1, class I2> requires Common<I1, I2> constexpr bool operator>=( const counted_iterator<I1>& x, const counted_iterator<I2>& y);

Requires: x and y shall refer to elements of the same sequence ([iterators.counted]).

Effects: Equivalent to: return !(x < y);

9.7.6.2.14 counted_iterator non-member functions [counted.iter.nonmember]

template <class I1, class I2> requires Common<I1, I2> constexpr difference_type_t<I2> operator-( const counted_iterator<I1>& x, const counted_iterator<I2>& y);

Requires: x and y shall refer to elements of the same sequence ([iterators.counted]).

Effects: Equivalent to: return y.cnt - x.cnt;

template <class I> constexpr difference_type_t<I> operator-( const counted_iterator<I>& x, default_sentinel y);

Effects: Equivalent to: return -x.cnt;

template <class I> constexpr difference_type_t<I> operator-( default_sentinel x, const counted_iterator<I>& y);

Effects: Equivalent to: return y.cnt;

template <RandomAccessIterator I> constexpr counted_iterator<I> operator+( difference_type_t<I> n, const counted_iterator<I>& x);

Requires: n <= x.cnt.

Effects: Equivalent to: return x + n;

friend constexpr rvalue_reference_t<I> iter_move(const counted_iterator& i) noexcept(see below) requires InputIterator<I>;

Effects: Equivalent to: return ranges::iter_move(i.current);

Remarks: The expression in noexcept is equivalent to:

noexcept(ranges::iter_move(i.current))

template <IndirectlySwappable<I> I2> friend constexpr void iter_swap(const counted_iterator& x, const counted_iterator<I2>& y) noexcept(see below);

Effects: Equivalent to ranges::iter_swap(x.current, y.current).

Remarks: The expression in noexcept is equivalent to:

noexcept(ranges::iter_swap(x.current, y.current))

template <Iterator I> constexpr counted_iterator<I> make_counted_iterator(I i, difference_type_t<I> n);

Requires: n >= 0.

Returns: counted_iterator<I>(i, n).