最終更新:2026-10-12
STL typename ソースコード解析¶
STLの低層ソースコードには以下の数行があり、typedefとtypenameが併用されています。複雑に見えますが、いったい何を意味するのか、今日は一緒に解析してみましょう!
template<typename _Iterator>
struct iterator_traits
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
typenameのよくある使い方¶
まずtypenameのよくある使い方を学びましょう:
上記はあくまでサンプルプログラムで、比較をきちんと行うには特殊化バージョンも考慮する必要があります。ここで、上のコードのtypenameをclassに置き換えても同じように動くと思うかもしれません。その通りです!では疑問が生じます。この2つの方法には違いがあるのでしょうか?C++ Primerを調べてみると、両者はまったく同じであることがわかります。
クラススコープ¶
クラスの外部からクラス内の名前にアクセスするとき、クラススコープ演算子を使えます。MyClass::nameのような呼び出しには通常3種類あります:**静的データメンバ、静的メンバ関数、ネストした型**です:
struct MyClass {
static int A; //静态成员
static int B(){cout<<"B()"<<endl; return 100;} //静态函数
typedef int C; //嵌套类型
struct A1 { //嵌套类型
static int s;
};
};
呼び出すときは、直接呼び出せます:
完全な例での試行¶
typenameの例に戻りましょう:
このコードの目的は何でしょうか?多くの人の第一反応は「iterというポインタを定義し、それが指す型はクラススコープTに含まれるiteratorである」と思うでしょう。次のような、iterator型を含む構造が存在すると考えられます:
呼び出しは次の通りです:
こうなると、iterの行のコードは明確で、MyIterator::iterator型のポインタです。私たちはそのように推測しますが、実際はどうでしょうか?
しかし、T::iteratorのような場合はどうでしょうか?Tはテンプレートの型パラメータなので、テンプレートがインスタンス化されるまでどの型なのかわかりません。ましてや内部のiteratorはなおさらです。先ほどのクラススコープの説明から、T::iteratorは実際には次の3種類のいずれにもなり得ることがわかります:
- 静的データメンバ
- 静的メンバ関数
- ネストした型
前の例のContainsAType::iteratorはネストした型なので、まったく問題ありません。しかし、静的データメンバだった場合はどうなるでしょうか?もしfooテンプレート関数を次のような型でインスタンス化したら:
すると、T::iterator * iter;はコンパイラによってMyIterator::iterator * iter;とインスタンス化されます。これは何でしょうか?先頭にあるのは型ではなく静的メンバ変数なので、これは乗算式になってしまいます。ただしiterはここでは定義されていないため、コンパイラはエラーを出します:
typename¶
テンプレート定義においてテンプレートパラメータに依存する名前については、インスタンス化時の引数の中にその型名が存在する場合か、その名前の前にtypenameキーワードが付けられている場合にのみ、コンパイラはその名前を型として扱います。この2つの場合以外、型として扱われることは決してありません。
したがって、T::iteratorが変数ではなく型であることをコンパイラに直接伝えたい場合は、typenameで修飾するだけです:
これでコンパイラはT::iteratorが型であると確定でき、インスタンス化の時期まで待つ必要がなくなり、前述の曖昧さが解消されます。
ソースコード解析¶
STLのソースコードに戻りましょう。
template<typename _Iterator>
struct iterator_traits
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
上を見れば一発でわかります。typenameを使ってコンパイラに_Iterator::iterator_categoryが型であることを伝え、typedefで名前を付け直しているだけです。残りも同様です!
関連トピック¶
- STL array ソースコード解析 | C++那些事
- STL string 深入解析 | C++那些事
- STL string 面接問題解説 | C++那些事
- STL deque ソースコード解析 | C++那些事
- STL 空基底クラス最適化 EBO | C++那些事
- STL 手書きハッシュテーブル実装 | C++那些事
- STL hashtable ハッシュテーブル | C++那些事
- STL イテレータソースコード解析 | C++那些事
- STL list ソースコード解析 | C++那些事
- STL map と multimap | C++那些事