9

私たちが知っていることstd::advanceは次のとおりです。

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

目的

イテレータin要素ごとに進めます。

iがランダムアクセスイテレータの場合、関数は1回またはoperator+を使用します。それ以外の場合、関数は要素が進むまでoperator-増加または減少演算子(operator++または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などの 1 つ) であるためiterator_category()、関数呼び出しではないことに注意してください。その型の一時的な prvalueを構築する式です。の適切なオーバーロード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、選択したタグ タイプのインスタンスである名前のない引数を 3 番目の引数として受け取ります。

于 2013-03-12T18:04:47.487 に答える
1

std::iterator_traits::iterator_categoryイテレータの型が何であるかを把握するために使用できると思います。

それに基づいて、物事を進める方法を決定することができます。

于 2013-03-12T18:04:47.450 に答える