Iterators: What Must Be Done?

Whenever I need to implement a custom iterator type in C++ I immediately remember nothing about what the standard has to say about the requirements for each iterator category, so here is a collation of cppreference links and examples describing what must be done to implement a custom iterator type.

Iterator

All iterator types must be CopyConstructible, CopyAssignable, Destructible, and Swappable; have the member types required by std::iterator_traits; and support the following expressions.

Expression Return Type
*r unspecified
++r iterator&
struct iterator {
  using difference_type = std::ptrdiff_t;
  using value_type = ?;
  using pointer = value_type*;
  using reference = value_type&;
  using iterator_category = ?;

  iterator(const iterator& rhs);
  iterator(iterator&& rhs);
  iterator& operator=(const iterator& rhs);
  iterator& operator=(iterator&& rhs);
  void swap(iterator& iter);

  reference operator*();

  iterator& operator++();
};

void swap(iterator& lhs, iterator& rhs);

InputIterator

In addition to the Iterator requirements, an InputIterator must also be EqualityComparable and support the following expressions.

Expression Return Type
i != j contextually convertible to bool
*i reference, convertible to value_type
i->m
++i input_iterator&
(void)i++ convertible to value_type
*i++
struct input_iterator {
  using difference_type = std::ptrdiff_t;
  using value_type = ?;
  using pointer = value_type*;
  using reference = value_type&;
  using iterator_category = std::input_iterator_tag;

  input_iterator(const input_iterator& rhs);
  input_iterator(input_iterator&& rhs);
  input_iterator& operator=(const input_iterator& rhs);
  input_iterator& operator=(input_iterator&& rhs);
  void swap(input_iterator& iter);

  bool operator==(const input_iterator& rhs);
  bool operator!=(const input_iterator& rhs);

  reference operator*();
  pointer operator->();

  input_iterator& operator++();
  input_iterator& operator++(int);
};

void swap(input_iterator& lhs, input_iterator& rhs);

OutputIterator

In addition to the Iterator requirements, an OutputIterator must also be a class type or a pointer type and support the following expressions.

Expression Return Type
*r = o (not used)
++r output_iterator&
r++ convertible to const output_iterator&
*r++ = o (not used)
struct output_iterator {
  using difference_type = std::ptrdiff_t;
  using value_type = ?;
  using pointer = value_type*;
  using reference = value_type&;
  using iterator_category = std::output_iterator_tag;

  output_iterator(const output_iterator& rhs);
  output_iterator(output_iterator&& rhs);
  output_iterator& operator=(const output_iterator& rhs);
  output_iterator& operator=(output_iterator&& rhs);
  void swap(output_iterator& iter);

  reference operator*();

  output_iterator& operator++();
  output_iterator operator++(int);
};

void swap(output_iterator& lhs, output_iterator& rhs);

ForwardIterator

In addition to the InputIterator requirements, a ForwardIterator must also be DefaultConstructible; support multiple iteration passes; std::iterator_traits<forward_iterator>::reference must be exactly T& satisfies OutputIterator or exactly const T& otherwise; and support the following expressions.

Expression Return Type
i++ forward_iterator
*i++ reference
struct forward_iterator {
  using difference_type = std::ptrdiff_t;
  using value_type = ?;
  using pointer = value_type*;
  using reference = value_type&;
  using iterator_category = std::forward_iterator_tag;

  forward_iterator();
  forward_iterator(const forward_iterator& rhs);
  forward_iterator(forward_iterator&& rhs);
  forward_iterator& operator=(const forward_iterator& rhs);
  forward_iterator& operator=(forward_iterator&& rhs);
  void swap(forward_iterator& iter);

  bool operator==(const forward_iterator& rhs);
  bool operator!=(const forward_iterator& rhs);

  reference operator*();
  pointer operator->();

  forward_iterator& operator++();
  forward_iterator operator++(int);
};

void swap(forward_iterator& lhs, forward_iterator& rhs);

BidirectionalIterator

In addition to the ForwardIterator requirements, a BidirectionalIterator must also support the following expressions.

Expression Return Type
--a bidirectional_iterator&
a-- convertible to const bidirectional_iterator&
*a-- reference
struct bidirectional_iterator {
  using difference_type = std::ptrdiff_t;
  using value_type = ?;
  using pointer = value_type*;
  using reference = value_type&;
  using iterator_category = std::bidirectional_iterator_tag;

  bidirectional_iterator();
  bidirectional_iterator(const bidirectional_iterator& rhs);
  bidirectional_iterator(bidirectional_iterator&& rhs);
  bidirectional_iterator& operator=(const bidirectional_iterator& rhs);
  bidirectional_iterator& operator=(bidirectional_iterator&& rhs);
  void swap(bidirectional_iterator& iter);

  bool operator==(const bidirectional_iterator& rhs);
  bool operator!=(const bidirectional_iterator& rhs);

  reference operator*();
  pointer operator->();

  bidirectional_iterator& operator++();
  bidirectional_iterator operator++(int);
  bidirectional_iterator& operator--();
  bidirectional_iterator operator--(int);
};

void swap(bidirectional_iterator& lhs, bidirectional_iterator& rhs);

RandomAccessIterator

In addition to the BidirectionalIterator requirements, a RandomAccessIterator must support the following expressions.

Expression Return Type
r += n random_access_iterator&
a + n/n + a random_access_iterator
r -= n random_access_iterator&
i - n random_access_iterator
b - a difference_type
i[n] convertible to reference
a < b contextually convertible to bool
a >= b contextually convertible to bool
a <= b contextually convertible to bool
struct random_access_iterator {
  using difference_type = std::ptrdiff_t;
  using value_type = ?;
  using pointer = value_type*;
  using reference = value_type&;
  using iterator_category = std::random_access_iterator_tag;

  random_access_iterator();
  random_access_iterator(const random_access_iterator& rhs);
  random_access_iterator(random_access_iterator&& rhs);
  random_access_iterator& operator=(const random_access_iterator& rhs);
  random_access_iterator& operator=(random_access_iterator&& rhs);
  void swap(random_access_iterator& iter);

  bool operator==(const random_access_iterator& rhs);
  bool operator!=(const random_access_iterator& rhs);
  bool operator<(const random_access_iterator& rhs);
  bool operator<=(const random_access_iterator& rhs);
  bool operator>(const random_access_iterator& rhs);
  bool operator>=(const random_access_iterator& rhs);

  reference operator*();
  pointer operator->();
  reference operator[](difference_type n);

  random_access_iterator& operator++();
  random_access_iterator operator++(int);
  random_access_iterator& operator+=(difference_type n);
  random_access_iterator operator+(difference_type n);
  random_access_iterator& operator--();
  random_access_iterator operator--(int);
  random_access_iterator& operator-=(difference_type n);
  random_access_iterator operator-(difference_type n);
};

void swap(random_access_iterator& lhs, random_access_iterator& rhs);

Summary

There they are, code snippets to get started implementing custom iterator types in C++. I will find these useful in future, I hope you do too. If there are any mistakes or glaring omissions please let know.