9

我们所知道std::advance的如下:

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

目的

in元素推进迭代器。

如果i是随机访问迭代器,则该函数使用一次operator+or operator-,否则,该函数重复使用递增或递减运算符 ( operator++or operator--),直到n元素被推进。


我的问题如下:如何std::advance实现以识别是否it是随机访问迭代器?它怎么知道它可以使用operator+而不是operator++

4

2 回答 2

18

通过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作为它们的第三个参数接收一个未命名的参数,该参数是它们选择的标记类型的一个实例。

于 2013-03-12T18:04:47.487 回答
1

我想它可以std::iterator_traits::iterator_category用来确定迭代器的类型。

在此基础上,它可以决定如何推进事情。

于 2013-03-12T18:04:47.450 回答