テンプレートの中でほかのテンプレートクラスのメンバ型を使う方法: typename や template の別の用法について

あるテンプレート関数(テンプレート型引数 T)で,例えば std::vector::iterator itr を定義しようとすると,コンパイルエラーとなる(std::vector::iterator が型であると認識されない).この場合 typename std::vector::iterator itr のように,前に typename をつけて,型であることを明示する.もし,iterator に相当するものが,テンプレートクラスの場合,template キーワードを使ってテンプレートであることを明示しなければならない.

例えば,

template <typename T1>
struct TTest
{
  struct TIn
    {
      double X;
    };
};

こんな構造体があったとして,

template <typename T1>
void Func (void)
{
  TTest<T1>::TIn  test;
  test.X= 1.2;
  cout<<"test.X= "<<test.X<<endl;
}

のような感じで TTest::TIn のインスタンスを生成したいとする.これはコンパイルエラーとなる.g++ の場合(51行目が当該箇所),

tmpl-in-struct.cpp: In function 'void Func()':
tmpl-in-struct.cpp:51: error: expected ';' before 'test'
tmpl-in-struct.cpp:52: error: 'test' was not declared in this scope
tmpl-in-struct.cpp: In function 'void Func() [with T1 = int]':
tmpl-in-struct.cpp:58:   instantiated from here
tmpl-in-struct.cpp:51: error: dependent-name 'TTest::TIn' is parsed as a non-type, but instantiation yields a type
tmpl-in-struct.cpp:51: note: say 'typename TTest::TIn' if a type is meant

のようなエラーを吐く.よく読めば,typename を使えばいいと分かる.つまり,

  typename TTest<T1>::TIn  test;

とすればよい.これでコンパイルが通る.

次に,TIn もテンプレートの場合:

template <typename T1>
struct TTest
{
  template <typename T2>
  struct TIn
    {
      T2 X;
    };
};

この場合,

template <typename T1, typename T2>
void Func (void)
{
  typename TTest<T1>::TIn<T2>  test;
  test.X= 1.2;
  cout<<"test.X= "<<test.X<<endl;
}

とするだけだと,コンパイルエラーとなる.g++ の場合(26行目が当該箇所),

tmpl-in-struct.cpp:26: error: non-template 'TIn' used as template
tmpl-in-struct.cpp:26: note: use 'TTest<T1>::template TIn' to indicate that it is a template
tmpl-in-struct.cpp:26: error: declaration does not declare anything
tmpl-in-struct.cpp:27: error: 'test' was not declared in this scope

のようなエラーを吐く.TTest::TIn がテンプレートと認識されていないようだ.認識させるためには,エラーに書いてあるように,template キーワードを使って,

  typename TTest<T1>::template TIn<T2>  test;

とすればよいらしい.この template キーワードの使い方は今日初めて知った.