Iterators Quick Reference
C++ iterator categories, requirements, traits, adapters, sentinel iterators, and C++20 ranges concepts.
Iterator Categories
cpp
InputIterator → can read forward, single-pass (istream)
OutputIterator → can write forward, single-pass (ostream, back_inserter)
ForwardIterator → read+write forward, multi-pass (forward_list)
BidirectionalIterator → + can go backward (list, map, set)
RandomAccessIterator → + jump by n, compare (vector, deque, array)
ContiguousIterator → + contiguous memory (C++17: vector, array, string)C++20 Concept Hierarchy
cpp
#include <iterator>
// Concepts (C++20)
std::input_iterator<I> // supports *it, ++it
std::output_iterator<I, T> // supports *it = val, ++it
std::forward_iterator<I> // input + default-constructible + multipass
std::bidirectional_iterator<I> // forward + --it
std::random_access_iterator<I> // bidirectional + it+n, it[n], it1-it2
std::contiguous_iterator<I> // random access + contiguous memory
// Range concepts
std::ranges::range<R> // has begin() + end()
std::ranges::sized_range<R> // + size()
std::ranges::contiguous_range<R> // contiguous memory
std::ranges::viewable_range<R> // can be converted to viewIterator Traits
cpp
#include <iterator>
// Access category and value type of any iterator
using I = std::vector<int>::iterator;
std::iterator_traits<I>::value_type; // int
std::iterator_traits<I>::difference_type; // ptrdiff_t
std::iterator_traits<I>::reference; // int&
std::iterator_traits<I>::pointer; // int*
std::iterator_traits<I>::iterator_category; // std::random_access_iterator_tag
// C++20 shorthand (concept-based)
std::iter_value_t<I> // int
std::iter_reference_t<I> // int&
std::iter_difference_t<I> // ptrdiff_t
// Check category
using Cat = std::iterator_traits<I>::iterator_category;
std::is_same_v<Cat, std::random_access_iterator_tag> // true
// With concepts (C++20):
std::random_access_iterator<I> // trueIterator Operations
cpp
std::vector<int> v{1,2,3,4,5};
auto it = v.begin();
// Universal (all categories)
*it // dereference: 1
++it // advance: points to 2
// Bidirectional+
--it // retreat: back to 1
// Random access only
it + 3 // advance by 3 (doesn't modify it)
it[2] // same as *(it + 2)
it2 - it1 // distance (signed)
it1 < it2 // comparison
// std::advance (works for all categories)
std::advance(it, 3); // advance by 3 (uses += for random, ++ for others)
std::advance(it, -1); // only for bidirectional+
// std::distance (works for all categories)
auto d = std::distance(v.begin(), v.end()); // 5
// std::next / std::prev (non-mutating)
auto it2 = std::next(it, 2); // it + 2 (new iterator)
auto it3 = std::prev(it, 1); // it - 1 (new iterator)Iterator Adapters
cpp
// reverse_iterator
std::vector<int> v{1,2,3,4,5};
for (auto it = v.rbegin(); it != v.rend(); ++it)
std::print("{} ", *it); // 5 4 3 2 1
// back_insert_iterator
std::vector<int> dst;
std::copy(v.begin(), v.end(), std::back_inserter(dst)); // appends
// front_insert_iterator (deque, list)
std::deque<int> dq;
std::copy(v.begin(), v.end(), std::front_inserter(dq)); // prepends
// insert_iterator (at a position)
std::list<int> lst{1,2,3};
auto pos = std::next(lst.begin());
std::copy(v.begin(), v.end(), std::inserter(lst, pos));
// istream_iterator
std::istream_iterator<int> in{std::cin}, eof;
std::vector<int> nums{in, eof};
// ostream_iterator
std::ostream_iterator<int> out{std::cout, ", "};
std::copy(v.begin(), v.end(), out); // 1, 2, 3, 4, 5,
// move_iterator (move elements instead of copy)
std::vector<std::string> src{"a", "b", "c"};
std::vector<std::string> dst2(std::make_move_iterator(src.begin()),
std::make_move_iterator(src.end()));
// src elements are moved (left in valid but unspecified state)Sentinel Iterators (C++20)
A sentinel is a type that marks the end — it doesn't need to be the same type as the iterator:
cpp
// Null-terminated string range using sentinel
struct NullSentinel {};
struct CStrIterator {
const char* ptr;
char operator*() const { return *ptr; }
CStrIterator& operator++() { ++ptr; return *this; }
bool operator==(NullSentinel) const { return *ptr == '\0'; }
};
// Ranges-compatible: begin() returns CStrIterator, end() returns NullSentinel
struct CStrRange {
const char* str;
CStrIterator begin() const { return {str}; }
NullSentinel end() const { return {}; }
};
for (char c : CStrRange{"hello"})
std::print("{}", c); // h e l l oWriting a Custom Iterator
cpp
// Random access iterator for a strided view
template<typename T>
class StridedIterator {
T* ptr_;
size_t stride_;
public:
using value_type = T;
using reference = T&;
using pointer = T*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
StridedIterator(T* p, size_t s) : ptr_{p}, stride_{s} {}
reference operator*() const { return *ptr_; }
pointer operator->() const { return ptr_; }
reference operator[](difference_type n) { return ptr_[n * stride_]; }
StridedIterator& operator++() { ptr_ += stride_; return *this; }
StridedIterator operator++(int) { auto tmp = *this; ++*this; return tmp; }
StridedIterator& operator--() { ptr_ -= stride_; return *this; }
StridedIterator operator--(int) { auto tmp = *this; --*this; return tmp; }
StridedIterator operator+(difference_type n) const { return {ptr_ + n*stride_, stride_}; }
StridedIterator operator-(difference_type n) const { return {ptr_ - n*stride_, stride_}; }
difference_type operator-(const StridedIterator& o) const { return (ptr_ - o.ptr_) / stride_; }
auto operator<=>(const StridedIterator&) const = default;
};