Iterators are a generalization of pointers that allow a programmer to work with different data structures
(containers) in a uniform manner. To be able to construct template algorithms that work correctly and
efficiently on different types of data structures, we need to formalize not just the interfaces but also the
semantics and complexity assumptions of iterators. Iterators are objects that have operator* returning a
value of some class or built-in type T called a value type of the iterator. For every iterator type X for which
equality is defined, there is a corresponding signed integral type called the distance type of the iterator.
Since iterators are a generalization of pointers, their semantics is a generalization of the semantics of
pointers in C++. This assures that every template function that takes iterators works with regular pointers.
Depending on the operations defined on them, there are five categories of iterators: input iterators, output
iterators, forward iterators, bidirectional iterators and random access iterators. Forward iterators satisfy all the
requirements of the input and output iterators and can be used whenever either kind is specified.
Bidirectional iterators satisfy all the requirements of the forward iterators and can be used whenever a
forward iterator is specified. Random access iterators satisfy all the requirements of bidirectional iterators
and can be used whenever a bidirectional iterator is specified. There is an additional attribute that forward,
bidirectional and random access iterators might have, that is, they can be mutable or constant depending on
whether the result of the operator* behaves as a reference or as a reference to a constant. Constant iterators
do not satisfy the requirements for output iterators.