テンプレートあれこれ (4) -- typename の役割

typename というキーワードには、2通りの用法がある。 "static" もそうだが、同一のキーワードに複数の意味を持たせるのは、 C++ の悪い癖だな。なんとかしてほしいところ。

で、typename の一つの意味は、テンプレート引数として 「型」を取ることを宣言する場合。 これは、"class" キーワードで置換できる。 たとえば、次の (A) と (B) は同値である。

  template<typename T> class Foo;  // (A)
  template<class T> class Foo;     // (B) 

まあ、これは誰でも知っていると思う。

typename には、もう一つ、後続する識別子が 「型名」であることを明示するという重要な働きがある。たとえば、

  template<class T> class Foo {
  public:
    T::value_type foo() const;
  };

のようなテンプレートの定義があったとして、コンパイラはこれを解析できるだろうか? T に何か具体的なクラス名が与えられていれば解析可能だろうが、 いきなりこのテンプレートの定義を見せられても、T が何者であるか不明な時点では、 T::value_type も果たして何かの型であるかどうかは分からない、と言うべきであろう。 あるいは次の例。

  template<class T> class Foo {
  public:
    void  foo() {
      T::value_type *p;
    }
  };

ここで太字にした文は、ポインタ p の宣言ではなくて、 T::value_typep の乗算とみなされてしまう。

このような時には、プログラマがコンパイラに対して 「T::value_type は何かの型を表しているぞよ」 ということを教えてやる必要がある。そのためのキーワードが typename なのである。

  template<class T> class Foo {
  public:
    typename T::value_type foo() const;
  };
  template<class T> class Foo {
  public:
    void  foo() {
      typename T::value_type *p;
    }
  };
(2002-07-04 注記) しかしながら、Microsoft の VC++ だと、typename を付けなくても正しくコンパイルできてしまう。 VC++ って、妙なところで賢いなあ。逆に、おもに VC++ を対象にソースを書いている人は、 意識して typename を付けるようにしましょう。

この typename の例は、STL の iterator_traits あたりを見ると、 山ほど出てくる。たとえば、次の通り。

  template<class Iterator> struct iterator_traits {
    typedef typename Iterator::value_type value_type;
  };

STL のソースを読むときなど、ちょっと注意してみるとよいだろう。


初出: 2002年5月14日

C++ ラビリンスの目次へ


ホームページへ / Last modified: 2002-07-04 14:09:27 JST
Created by OKA Toshiyuki < oka-t@fides.dti.ne.jp >