8

アプリケーションのプロファイリングを行っているときに、gcc 4.7.1 に同梱されている標準ライブラリの実装の一部に出くわしました。それはinclude/g++-v4/bits/vector.tcc

template<typename _Tp, typename _Alloc>
template<typename _ForwardIterator>
  void
  vector<_Tp, _Alloc>::
    _M_range_insert(iterator __position, _ForwardIterator __first,
          _ForwardIterator __last, std::forward_iterator_tag)
  {
     …
  }

関数シグネチャの最後の引数が単なるタグであることに気付き、なぜここにあるのか疑問に思い始めました。このページをざっと見てみると、それstd::forward_iterator_tagが空の構造であることがわかります。ここでの役割は何ですか?明らかにそれは関数にとって役に立たず、レジスターまたはスタック上のスペースを浪費する可能性があります。なぜ?

4

5 に答える 5

6

異なるオーバーロードを区別するため_M_range_insert

このリファレンスはもう少し優れているようで、タグ構造の使用方法の例があります。

于 2013-07-02T10:17:43.013 に答える
4

リンクを引用するリスクがあります..

イテレータのカテゴリを前方イテレータとして識別するための空のクラス:

関数が適切に動作できるように、イテレータの種類を識別するためのタグとして使用され_M_range_insertます。これは型名であるため、さまざまなオーバーロードをトリガーするために使用できます。

私の実装では、私は持っています

void _Insert(const_iterator _Where, _Iter _First, _Iter _Last,
            _Int_iterator_tag)

void _Insert(const_iterator _Where, _Iter _First, _Iter _Last,
            input_iterator_tag)

void _Insert(const_iterator _Where, _Iter _First, _Iter _Last, 
            forward_iterator_tag)

他のオーバーロードの中でも。

于 2013-07-02T10:16:45.457 に答える
1

これはテンプレート メタプログラミング機構の一部であり、引数の特性に基づいて適切なオーバーロードを選択するために使用されます。たとえば、ランダム アクセス イテレータがある場合は、それを利用してそれらの間の距離をチェックし、挿入前に予約することができます。一方、距離をチェックする前方イテレータのみが O(n) になる場合は、そうしないでください。プッシュバックするだけで、複数の再配置が発生し、遅くなる可能性があります。また、コンパイラはこれらの空の構造体を最適化するため、実行時のペナルティはありません。

于 2013-07-02T10:23:00.037 に答える
1

ベクターに挿入するためのオーバーロードがいくつかあり、そのうちのいくつかはコンストラクター用に複製されています。これらのオーバーロードのうち 2 つは、ベクトル要素が整数型の場合に競合します。

iterator insert( const_iterator pos, size_type count, const T& value );

template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );

vector<int>と callがある場合vec.insert(vec.bgein(), 5, 4)、値 4 の 5 倍を挿入することを意味していることは間違いありませInputItint

この問題とその他の振る舞いの問題を解決するために、標準ライブラリの実装者は、いくつかの特性と一連のタグ クラスを発明しました。特性は、Karthik T が回答で述べたように、3 つの異なるタグを与えるテンプレート メタ関数です。

  • _Int_iterator_tagInputIt整数型の場合
  • forward_iterator_tagifInputItは前方反復子 (ランダム アクセス反復子を含む) です。
  • input_iterator_tagifInputItは前方反復子ではない反復子型です

_M_range_insert次に、さまざまなタグタイプを追加のパラメーターとして取り、それぞれが正しいことを行う、のオーバーロードの束を取得します。つまり、

  • Int-Tag のオーバーロードは、テンプレート化されていない最初のオーバーロードinsert(またはその実装)にリダイレクトされます。
  • 前方イテレータのオーバーロードはreserve(std::distance(first,last))、その後、イテレータ範囲から要素を呼び出してコピーします
  • 単純な入力反復子のオーバーロードは要素をコピーするだけで、複数の再割り当てが発生する可能性があります。reserve入力イテレータは 1 回しか評価できないため (istream イテレータなど)、 を呼び出すことはできません。

テンプレート化された挿入メソッドは、概念的に次のようになります。

template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last )
{
  return _M_range_insert(pos, first, last, InsertIteratorTraits<InputIt>::tag_type());
}
于 2013-07-02T11:49:26.117 に答える