Как реализован std :: advance для изменения поведения типа итератора?

Что мы знаем о std::advance является следующим:

template <class InputIterator, class Distance>
void advance (InputIterator& i, Distance n);

Цель

Продвигает итератор i от n элементы.

Если i является итератором произвольного доступа, функция использует один раз operator+ или же operator-в противном случае функция многократно использует оператор увеличения или уменьшения (operator++ или же operator--) до тех пор n элементы были продвинуты.


Мой вопрос заключается в следующем:
Как std::advance реализован так, что он распознает, если it такое итератор произвольного доступа или нет? Как он знает, что может использовать operator+ вместо operator++?

9

Решение

Через iterator_traits а также отправка тегов:

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());
}

Обратите внимание, что iterator_category это тип (один из std::input_iterator_tag и т. д.) iterator_category() не является вызовом функции; это выражение, которое создает временное значение этого типа. Соответствующая перегрузка advance_impl затем выбирается нормальным разрешением перегрузки. Это называется отправка тегов. Эквивалентно можно написать:

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);
}

Перегрузки advance_impl получают в качестве третьего аргумента безымянный аргумент, который является экземпляром выбранного типа тега.

18

Другие решения

Я полагаю, это может использовать std::iterator_traits::iterator_category выяснить, какой тип итератора.

Исходя из этого, он может решить, как продвигать вещи.

1

По вопросам рекламы [email protected]