In generic programming, especially when writing STL-like containers and iterators, it’s essential to understand the role of iterator_traits
and when you should or should not use it.
This guide explains:
- What
iterator_traits
is - Why it is used in
reverse_iterator
- Why it is not used in
random_access_iterator
- The general rule for when to use
iterator_traits
- Code examples and analogies
iterator_traits
is a traits class that extracts type information from an iterator type.
It gives you access to:
value_type
pointer
reference
difference_type
iterator_category
template <typename Iterator>
void foo(Iterator it) {
typedef typename ft::iterator_traits<Iterator>::value_type T;
...
}
This allows foo()
to work with both:
- Class iterators (
ft::random_access_iterator<T>
) - Raw pointers (
T*
)
Because reverse_iterator
is a generic adapter over any iterator type Iter
:
template <typename Iter>
class reverse_iterator {
public:
typedef typename ft::iterator_traits<Iter>::value_type value_type;
typedef typename ft::iterator_traits<Iter>::reference reference;
typedef typename ft::iterator_traits<Iter>::pointer pointer;
typedef typename ft::iterator_traits<Iter>::difference_type difference_type;
typedef typename ft::iterator_traits<Iter>::iterator_category iterator_category;
};
This works for:
ft::random_access_iterator<T>
const T*
,T*
(raw pointers)- Any future custom iterator class
Because raw pointers like int*
do not have member types like value_type
or reference
.
// Invalid for raw pointer
typename int*::value_type // ❌ compiler error
Traits fix that:
typename ft::iterator_traits<int*>::value_type // ✅ int
Your ft::random_access_iterator<T>
is the iterator being described.
template <typename T>
class random_access_iterator {
public:
typedef T* pointer;
typedef T& reference;
typedef T value_type;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
};
If you wrote this using iterator_traits
:
typedef typename ft::iterator_traits<T>::value_type value_type; // ❌ invalid
It assumes T
is already an iterator — but in your case, it's the value type, like int
.
So this would be a circular, incorrect use of traits.
random_access_iterator<T>
is like creating your own ID card.iterator_traits<Iter>
is like a scanner that reads ID cards.
random_access_iterator
defines the traits (name, age, etc.).iterator_traits
is used by others (likereverse_iterator
) to extract those traits.
Scenario | Use iterator_traits ? |
Why? |
---|---|---|
Inside random_access_iterator |
❌ No | You're defining the iterator |
Inside reverse_iterator |
✅ Yes | You're adapting another iterator |
Inside algorithms (advance ) |
✅ Yes | To support any iterator type (pointer, class) |
With raw pointers (int* ) |
✅ Yes | Only traits can describe them |
This should work:
ft::iterator_traits<ft::random_access_iterator<int> >::value_type // ✅ int
ft::iterator_traits<int*>::value_type // ✅ int
But this will fail:
typename int*::value_type // ❌ compiler error: no such member
Use
iterator_traits<T>
when you don’t own or define the iteratorT
.
But when you're defining the iterator class itself — don't use iterator_traits
inside it.
Links: