9 Iterators library [iterators]

9.3 Iterator requirements [iterator.requirements]

9.3.3 Iterator associated types [iterator.assoc.types]

To implement algorithms only in terms of iterators, it is often necessary to determine the value and difference types that correspond to a particular iterator type. Accordingly, it is required that if WI is the name of a type that satisfies the WeaklyIncrementable concept ([iterators.weaklyincrementable]), R is the name of a type that satisfies the Readable concept ([iterators.readable]), and II is the name of a type that satisfies the InputIterator concept ([iterators.input]) concept, the types

difference_type_t<WI>
value_type_t<R>
iterator_category_t<II>

be defined as the iterator's difference type, value type and iterator category, respectively.

9.3.3.1 difference_type [iterator.assoc.types.difference_type]

difference_type_t<T> is implemented as if:

  template <class> struct difference_type { };

  template <class T>
  struct difference_type<T*>
    : enable_if<is_object<T>::value, ptrdiff_t> { };

  template <class I>
  struct difference_type<const I> : difference_type<decay_t<I>> { };

  template <class T>
    requires requires { typename T::difference_type; }
  struct difference_type<T> {
    using type = typename T::difference_type;
  };

  template <class T>
    requires !requires { typename T::difference_type; } &&
      requires(const T& a, const T& b) { { a - b } -> Integral; }
  struct difference_type<T>
    : make_signed< decltype(declval<T>() - declval<T>()) > {
  };

  template <class T> using difference_type_t
    = typename difference_type<T>::type;

Users may specialize difference_type on user-defined types.

9.3.3.2 value_type [iterator.assoc.types.value_type]

A Readable type has an associated value type that can be accessed with the value_type_t alias template.

  template <class> struct value_type { };

  template <class T>
  struct value_type<T*>
    : enable_if<is_object<T>::value, remove_cv_t<T>> { };

  template <class I>
    requires is_array<I>::value
  struct value_type<I> : value_type<decay_t<I>> { };

  template <class I>
  struct value_type<const I> : value_type<decay_t<I>> { };

  template <class T>
    requires requires { typename T::value_type; }
  struct value_type<T>
    : enable_if<is_object<typename T::value_type>::value, typename T::value_type> { };

  template <class T>
    requires requires { typename T::element_type; }
  struct value_type<T>
    : enable_if<
        is_object<typename T::element_type>::value,
        remove_cv_t<typename T::element_type>>
    { };

  template <class T> using value_type_t
    = typename value_type<T>::type;

If a type I has an associated value type, then value_type<I>::type shall name the value type. Otherwise, there shall be no nested type type.

The value_type class template may be specialized on user-defined types.

When instantiated with a type I such that I::value_type is valid and denotes a type, value_type<I>::type names that type, unless it is not an object type ( ISO/IEC 14882:2014 §[basic.types]) in which case value_type<I> shall have no nested type type. [ Note: Some legacy output iterators define a nested type named value_type that is an alias for void. These types are not Readable and have no associated value types. — end note ]

When instantiated with a type I such that I::element_type is valid and denotes a type, value_type<I>::type names the type remove_cv_t<I::element_type>, unless it is not an object type ( ISO/IEC 14882:2014 §[basic.types]) in which case value_type<I> shall have no nested type type. [ Note: Smart pointers like shared_ptr<int> are Readable and have an associated value type. But a smart pointer like shared_ptr<void> is not Readable and has no associated value type. — end note ]

9.3.3.3 iterator_category [iterator.assoc.types.iterator_category]

iterator_category_t<T> is implemented as if:

  template <class> struct iterator_category { };

  template <class T>
  struct iterator_category<T*>
    : enable_if<is_object<T>::value, random_access_iterator_tag> { };

  template <class T>
  struct iterator_category<T const> : iterator_category<T> { };

  template <class T>
    requires requires { typename T::iterator_category; }
  struct iterator_category<T> {
    using type = see below;
  };

  template <class T> using iterator_category_t
    = typename iterator_category<T>::type;

Users may specialize iterator_category on user-defined types.

If T::iterator_category is valid and denotes a type, then the type iterator_category<T>::type is computed as follows:

  • If T::iterator_category is the same as or derives from std::random_access_iterator_tag, iterator_category<T>::type is ranges::random_access_iterator_tag.

  • Otherwise, if T::iterator_category is the same as or derives from std::bidirectional_iterator_tag, iterator_category<T>::type is ranges::bidirectional_iterator_tag.

  • Otherwise, if T::iterator_category is the same as or derives from std::forward_iterator_tag, iterator_category<T>::type is ranges::forward_iterator_tag.

  • Otherwise, if T::iterator_category is the same as or derives from std::input_iterator_tag, iterator_category<T>::type is ranges::input_iterator_tag.

  • Otherwise, if T::iterator_category is the same as or derives from std::output_iterator_tag, iterator_category<T> has no nested type.

  • Otherwise, iterator_category<T>::type is T::iterator_category

rvalue_reference_t<T> is implemented as if:

template <dereferenceable T> requires see below using rvalue_reference_t = decltype(ranges::iter_move(declval<T&>()));

The expression in the requires clause is equivalent to:

requires(T& t) { { ranges::iter_move(t) } -> auto&&; }