What we know about std::advance
is the following:
template <class InputIterator, class Distance>
void advance (InputIterator& i, Distance n);
Purpose
Advances the iterator i
by n
elements.
If i
is a Random Access Iterator, the function uses once operator+
or operator-
, otherwise, the function uses repeatedly the increase or decrease operator (operator++
or operator--
) until n
elements have been advanced.
My question is the following:
How is std::advance
implemented such that it recognizes if it
is a Random Access Iterator or not? How does it know it can use operator+
instead of operator++
?
std::advance in C++ std::advance advances the iterator 'it' by n element positions. Syntax : template void advance (InputIterator& it, Distance n); it : Iterator to be advanced n : Number of element positions to advance. This shall only be negative for random-access and bidirectional iterators.
std::distance Returns the number of elements between first and last . The behavior is undefined if last is not reachable from first by (possibly repeatedly) incrementing first .
Through iterator_traits
and tag dispatch:
template<class InputIterator, class Distance>
void advance_impl(InputIterator& i, Distance n, std::random_access_iterator_tag) {
i += n;
}
template<class InputIterator, class Distance>
void advance_impl(InputIterator& i, Distance n, std::bidirectional_iterator_tag) {
if (n < 0) {
while (n++) --i;
} else {
while (n--) ++i;
}
}
template<class InputIterator, class Distance>
void advance_impl(InputIterator& i, Distance n, std::input_iterator_tag) {
assert(n >= 0);
while (n--) ++i;
}
template<class InputIterator, class Distance>
void advance (InputIterator& i, Distance n) {
advance_impl(i, n,
typename std::iterator_traits<InputIterator>::iterator_category());
}
Note that iterator_category
is a type (one of std::input_iterator_tag
etc.), so iterator_category()
is not a function call; it's an expression that constructs a temporary prvalue of that type. The appropriate overload of advance_impl
is then selected by normal overload resolution. This is called tag dispatch. Equivalently one could write:
template<class InputIterator, class Distance>
void advance (InputIterator& i, Distance n) {
typename std::iterator_traits<InputIterator>::iterator_category the_tag;
advance_impl(i, n, the_tag);
}
The overloads of advance_impl
are receiving as their third argument an unnamed argument that is an instance of their chosen tag type.
I would imagine it may use std::iterator_traits::iterator_category
to figure out what the type of the iterator is.
Based on that, it can decide how to advance things.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With