93015


以下のような実装がiterator_traits構造体の実装として書かれていましたが、  
なぜ、Iterクラスの名前空間内にdifference_typeやvalue_typeのような型があるのでしょうか。  
僕の考えだと、template
としたとき、Iterが表すのは、templateの型名でしかないという認識だったのですが、その自分がtemplateとして定義したIterの中に、difference_typeなどの型があるのか不思議です。  
わかるかた教えていただけると助かります。

[code]

                struct iterator_traits {
                    typedef typename Iter::difference_type difference_type;
                    typedef typename Iter::value_type value_type;
                    typedef typename Iter::pointer pointer;
                    typedef typename Iter::reference reference;
                    typedef typename Iter::iterator_category iterator_category;
                    /*
                     * difference_type  イテレータの減算演算時の型
                     * value_type   イテレータの指す値型
                     * pointer  イテレータのポインタ型
                     * reference    イテレータの参照型
                     * iterator_category    イテレータのカテゴリ型
                     */
                };```
    
[/code]


CC BY-SA 4.0
2022-12-24T15:10:59.270
92992
2022-12-28T02:19:04.080
55503
question
c++
自分で定義したtemplate <class Iter>のIterの中に型名が存在している理由がわかりませんでした。


実体の分からない型`Iter`を使って何か処理をするテンプレートクラスや関数テンプレートを定義するのに必要になります。  
例えば以下のページで合計値を計算する`sum`関数テンプレートを定義していますが、イテレータ`Iterator`が指している値型`value_type`（`int`かもしれないし、`double`かもしれないし、その他かもしれないし）が提供されないと、合計値を格納する変数`result`や戻り値の型を決められないため処理を書けません。

<https://cpprefjp.github.io/reference/iterator/iterator_traits.html>

[code]

    // 範囲の合計値を計算する
    template <class Iterator>
    typename std::iterator_traits<Iterator>::value_type
        sum(Iterator first, Iterator last)
    {
      // イテレータの型から値型を取得する
      using value_type = typename std::iterator_traits<Iterator>::value_type;
    
      // 取得した値型の変数を定義し、合計値を計算する
      value_type result = value_type();
      for (; first != last; ++first) {
        result += *first;
      }
      return result;
    }
    
[/code]


CC BY-SA 4.0
2022-12-24T17:20:56.280
92994
2022-12-24T17:20:56.280
7291
92992
answer


`iterator_traits`にはポインタに対する特殊化が定義されています。

[code]

    template<class T>
    struct iterator_traits<T*> {
      typedef ptrdiff_t difference_type;
      typedef T value_type;
      typedef T* pointer;
      typedef T& reference;
      typedef random_access_iterator_tag iterator_category;
    };
    
[/code]

組み込みのポインタ型は直接的に`difference_type`を持っていないので、この`iterator_traits`とポインタに対する特殊化があることによって、コンテナ型がもつイテレータ型と、組み込みのポインタ型を共通して使えるようになります。

[code]

    typedef iterator_traits<vector<int>::iterator>::difference_type a;
    typedef iterator_traits<int*>::difference_type b;
    
[/code]


CC BY-SA 4.0
2022-12-25T13:27:28.453
93006
2022-12-28T02:19:04.080
2022-12-28T02:19:04.080
6088
6088
92992
answer


> なぜ、Iterクラスの名前空間内にdifference_typeやvalue_typeのような型があるのでしょうか。

考え方が逆です。

テンプレートパラメータ`Iter`がC++標準ライブラリの「イテレータ(iterator)」互換であれば、`Iter::difference_type`や`Iter::value_type`といった型名が提供されます。これらの型名を提供しないクラスは、C++イテレータと呼べないと言い換えても良いでしょう。

※注：例外事項として言語組込のポインタ(pointer)型に対してのみ
[`iterator_traits<T*>`のようなテンプレート特殊化](https://cpprefjp.github.io/reference/iterator/iterator_traits.html)
が行われます。[Akira Takahashiさん回答](https://ja.stackoverflow.com/a/93006/)も参照ください。

* * *

> Iterが表すのは、templateの型名でしかないという認識だったのですが、

ここまでは、正しい認識です。

> その自分がtemplateとして定義したIterの中に、difference_typeなどの型があるのか不思議です。

前述の通り、C++におけるイテレータクラスは`difference_type`などの型を提供しなければなりません。標準ライブラリ提供コンテナのイテレータは、全てのこの要請に従ったクラスとして実装されます。

仮にあなた自身がテンプレートパラメータ`Iter`に渡す「イテレータ」クラスを実装するのであれば、C++標準ライブラリ仕様が要求する外部インタフェース仕様に従わなければなりません。


CC BY-SA 4.0
2022-12-26T06:51:16.193
93015
2022-12-26T06:51:16.193
49
92992
answer