質問: ``` class A { class B { }; B b(); }; A::B A::b() { return B(); } template class C { class D { }; D d(); }; template C::D d() { return D(); } ``` C::D d() の行でエラーが出てしまいます。 VisualStudio2017 Community で実行したところ、以下のエラーメッセージが出ました。 構文エラー:識別子'D' なぜなのでしょうか。教えていただけると幸いです。
回答: こんにちは。 テンプレートの場合、テンプレート引数が確定するまで実体化されません。 なのでコンパイラはCを未知のクラスとして取り扱います。 プライマリーテンプレートしか定義されていないなら既知ですが、部分特殊化や特殊化されることも考慮しているのだと思います。 ということは、C::DのDはクラス名(型名)かもしれないし、メンバ変数名かもしれません。 このような時、特に指定しないとメンバ変数名として取り扱います。 そこで、Dが型名であることを明示的に示すために、typename指定します。 ``` template typename C::D d() { return D(); } ``` これでもまだエラーが出るかも知れません。(gccやclangではエラーが残ります。) return D();のD()を特定できないのです。 クラス・テンプレートのメンバ関数をクラス外定義する時、クラスの指定を省略できないようです。 この場合は省略せずに全部書く必要があるようです。恐らくCが未知扱いだからと思います。 ``` template typename C::D d() { return C::D(); } ``` こっちは typename を書かなくて良いのがちょっと不思議に感じますが、構文的にはコンストラクタ呼び出しなので省略できるようです。(gccとclangでは書いても通りました。)