9 Iterators library [iterators]

9.6 Iterator primitives [iterator.primitives]

To simplify the task of defining iterators, the library provides several classes and functions:

9.6.1 Iterator traits [iterator.traits]

For the sake of backwards compatibility, this document specifies the existence of an iterator_traits alias that collects an iterator's associated types. It is defined as if:

  template <InputIterator I> struct __pointer_type {        // exposition only
    using type = add_pointer_t<reference_t<I>>;
  };
  template <InputIterator I>
    requires requires(I i) { { i.operator->() } -> auto&&; }
  struct __pointer_type<I> {                                    // exposition only
    using type = decltype(declval<I>().operator->());
  };
  template <class> struct __iterator_traits { };                // exposition only
  template <Iterator I> struct __iterator_traits<I> {
    using difference_type = difference_type_t<I>;
    using value_type = void;
    using reference = void;
    using pointer = void;
    using iterator_category = output_iterator_tag;
  };
  template <InputIterator I> struct __iterator_traits<I> {  // exposition only
    using difference_type = difference_type_t<I>;
    using value_type = value_type_t<I>;
    using reference = reference_t<I>;
    using pointer = typename __pointer_type<I>::type;
    using iterator_category = iterator_category_t<I>;
  };
  template <class I>
    using iterator_traits = __iterator_traits<I>;

Note: iterator_traits is an alias template to prevent user code from specializing it.  — end note ]

Example: To implement a generic reverse function, a C++ program can do the following:

template <BidirectionalIterator I>
void reverse(I first, I last) {
  difference_type_t<I> n = distance(first, last);
  --n;
  while(n > 0) {
    value_type_t<I> tmp = *first;
    *first++ = *--last;
    *last = tmp;
    n -= 2;
  }
}

 — end example ]

9.6.2 Standard iterator traits [iterator.stdtraits]

To facilitate interoperability between new code using iterators conforming to this document and older code using iterators that conform to the iterator requirements specified in ISO/IEC 14882, three specializations of std::iterator_traits are provided to map the newer iterator categories and associated types to the older ones.

namespace std {
  template <experimental::ranges::Iterator Out>
  struct iterator_traits<Out> {
    using difference_type   = experimental::ranges::difference_type_t<Out>;
    using value_type        = see below;
    using reference         = see below;
    using pointer           = see below;
    using iterator_category = std::output_iterator_tag;
  };
}

The nested type value_type is computed as follows:

  • If Out::value_type is valid and denotes a type, then std::iterator_traits<Out>::value_type is Out::value_type.

  • Otherwise, std::iterator_traits<Out>::value_type is void.

The nested type reference is computed as follows:

  • If Out::reference is valid and denotes a type, then std::iterator_traits<Out>::reference is Out::reference.

  • Otherwise, std::iterator_traits<Out>::reference is void.

The nested type pointer is computed as follows:

  • If Out::pointer is valid and denotes a type, then std::iterator_traits<Out>::pointer is Out::pointer.

  • Otherwise, std::iterator_traits<Out>::pointer is void.

namespace std {
  template <experimental::ranges::InputIterator In>
  struct iterator_traits<In> { };

  template <experimental::ranges::InputIterator In>
    requires experimental::ranges::Sentinel<In, In>
  struct iterator_traits<In> {
    using difference_type   = experimental::ranges::difference_type_t<In>;
    using value_type        = experimental::ranges::value_type_t<In>;
    using reference         = see below;
    using pointer           = see below;
    using iterator_category = see below;
  };
}

The nested type reference is computed as follows:

  • If In::reference is valid and denotes a type, then std::iterator_traits<In>::reference is In::reference.

  • Otherwise, std::iterator_traits<In>::reference is experimental::ranges::reference_t<In>.

The nested type pointer is computed as follows:

  • If In::pointer is valid and denotes a type, then std::iterator_traits<In>::pointer is In::pointer.

  • Otherwise, std::iterator_traits<In>::pointer is experimental::ranges::iterator_traits<In>::pointer.

Let type C be experimental::ranges::iterator_category_t<In>. The nested type std::iterator_traits<In>::iterator_category is computed as follows:

  • If C is the same as or inherits from std::input_iterator_tag or std::output_iterator_tag, std::iterator_traits<In>::iterator_category is C.

  • Otherwise, if experimental::ranges::reference_t<In> is not a reference type, std::iterator_traits<In>::iterator_category is std::input_iterator_tag.

  • Otherwise, if C is the same as or inherits from experimental::ranges::random_access_iterator_tag, std::iterator_traits<In>::iterator_category is std::random_access_iterator_tag.

  • Otherwise, if C is the same as or inherits from experimental::ranges::bidirectional_iterator_tag, std::iterator_traits<In>::iterator_category is std::bidirectional_iterator_tag.

  • Otherwise, if C is the same as or inherits from experimental::ranges::forward_iterator_tag, std::iterator_traits<In>::iterator_category is std::forward_iterator_tag.

  • Otherwise, std::iterator_traits<In>::iterator_category is std::input_iterator_tag.

Note: Some implementations may find it necessary to add additional constraints to these partial specializations to prevent them from being considered for types that conform to the iterator requirements specified in ISO/IEC 14882. — end note ]

9.6.3 Standard iterator tags [std.iterator.tags]

It is often desirable for a function template specialization to find out what is the most specific category of its iterator argument, so that the function can select the most efficient algorithm at compile time. To facilitate this, the library introduces category tag classes which can be used as compile time tags for algorithm selection. [ Note: The preferred way to dispatch to more specialized algorithm implementations is with concept-based overloading. — end note ] The category tags are: input_iterator_tag, output_iterator_tag, forward_iterator_tag, bidirectional_iterator_tag and random_access_iterator_tag. For every input iterator of type I, iterator_category_t<I> shall be defined to be the most specific category tag that describes the iterator's behavior.

namespace std { namespace experimental { namespace ranges { inline namespace v1 {
  struct output_iterator_tag { };
  struct input_iterator_tag { };
  struct forward_iterator_tag : input_iterator_tag { };
  struct bidirectional_iterator_tag : forward_iterator_tag { };
  struct random_access_iterator_tag : bidirectional_iterator_tag { };
}}}}

Note: The output_iterator_tag is provided for the sake of backward compatibility.  — end note ]

Example: For a program-defined iterator BinaryTreeIterator, it could be included into the bidirectional iterator category by specializing the difference_type, value_type, and iterator_category templates:

template <class T> struct difference_type<BinaryTreeIterator<T>> {
  using type = ptrdiff_t;
};
template <class T> struct value_type<BinaryTreeIterator<T>> {
  using type = T;
};
template <class T> struct iterator_category<BinaryTreeIterator<T>> {
  using type = bidirectional_iterator_tag;
};

 — end example ]

9.6.4 Iterator operations [iterator.operations]

Since only types that satisfy RandomAccessIterator provide the + operator, and types that satisfy SizedSentinel provide the - operator, the library provides customization point objects ([customization.point.object]) advance, distance, next, and prev. These customization point objects use + and - for random access iterators and ranges that satisfy SizedSentinel (and are, therefore, constant time for them); for output, input, forward and bidirectional iterators they use ++ to provide linear time implementations.

The name advance denotes a customization point object ([customization.point.object]). It has the following function call operators:

template <Iterator I> constexpr void operator()(I& i, difference_type_t<I> n) const;

Requires: n shall be negative only for bidirectional iterators.

Effects: For random access iterators, equivalent to i += n. Otherwise, increments (or decrements for negative n) iterator i by n.

template <Iterator I, Sentinel<I> S> constexpr void operator()(I& i, S bound) const;

Requires: If Assignable<I&, S> is not satisfied, [i,bound) shall denote a range.

Effects:

  • If Assignable<I&, S> is satisfied, equivalent to i = std::move(bound).

  • Otherwise, if SizedSentinel<S, I> is satisfied, equivalent to advance(i, bound - i).

  • Otherwise, increments i until i == bound.

template <Iterator I, Sentinel<I> S> constexpr difference_type_t<I> operator()(I& i, difference_type_t<I> n, S bound) const;

Requires: If n > 0, [i,bound) shall denote a range. If n == 0, [i,bound) or [bound,i) shall denote a range. If n < 0, [bound,i) shall denote a range and (BidirectionalIterator<I> && Same<I, S>) shall be satisfied.

Effects:

  • If SizedSentinel<S, I> is satisfied:

    • If |n| >= |bound - i|, equivalent to advance(i, bound).

    • Otherwise, equivalent to advance(i, n).

  • Otherwise, increments (or decrements for negative n) iterator i either n times or until i == bound, whichever comes first.

Returns: n - M, where M is the distance from the starting position of i to the ending position.

The name distance denotes a customization point object. It has the following function call operators:

template <Iterator I, Sentinel<I> S> constexpr difference_type_t<I> operator()(I first, S last) const;

Requires: [first,last) shall denote a range, or (Same<S, I> && SizedSentinel<S, I>) shall be satisfied and [last,first) shall denote a range.

Effects: If SizedSentinel<S, I> is satisfied, returns (last - first); otherwise, returns the number of increments needed to get from first to last.

template <Range R> constexpr difference_type_t<iterator_t<R>> operator()(R&& r) const;

Effects: Equivalent to: return distance(ranges::begin(r), ranges::end(r)); ([range.access])

Remarks: Instantiations of this member function template may be ill-formed if the declarations in <experimental/ranges/range> are not in scope at the point of instantiation ( ISO/IEC 14882:2014 §[temp.point]).

template <SizedRange R> constexpr difference_type_t<iterator_t<R>> operator()(R&& r) const;

Effects: Equivalent to: return ranges::size(r); ([range.primitives.size])

Remarks: Instantiations of this member function template may be ill-formed if the declarations in <experimental/ranges/range> are not in scope at the point of instantiation ( ISO/IEC 14882:2014 §[temp.point]).

The name next denotes a customization point object. It has the following function call operators:

template <Iterator I> constexpr I operator()(I x) const;

Effects: Equivalent to: ++x; return x;

template <Iterator I> constexpr I operator()(I x, difference_type_t<I> n) const;

Effects: Equivalent to: advance(x, n); return x;

template <Iterator I, Sentinel<I> S> constexpr I operator()(I x, S bound) const;

Effects: Equivalent to: advance(x, bound); return x;

template <Iterator I, Sentinel<I> S> constexpr I operator()(I x, difference_type_t<I> n, S bound) const;

Effects: Equivalent to: advance(x, n, bound); return x;

The name prev denotes a customization point object. It has the following function call operators:

template <BidirectionalIterator I> constexpr I operator()(I x) const;

Effects: Equivalent to: --x; return x;

template <BidirectionalIterator I> constexpr I operator()(I x, difference_type_t<I> n) const;

Effects: Equivalent to: advance(x, -n); return x;

template <BidirectionalIterator I> constexpr I operator()(I x, difference_type_t<I> n, I bound) const;

Effects: Equivalent to: advance(x, -n, bound); return x;