VisualC++でテンプレートをCPP側で実装できない件
結論
VisualC++コンパイラの仕様上、CPPには実装できない。
但し、明示的実体化を行うことで、実装可能。
例
TemplateClass.h:テンプレートのヘッダ
template <class T> class TemplateClass { // コンストラクタ TemplateClass(T* t); int getValue(); };
TemplateClass.cpp:テンプレートの実装
#include "TemplateClass.h" // コンストラクタ TemplateClass<T>::TemplateClass(T* t) { this->t = t; } int TemplateClass<T>::getValue() { t->getValue(); }
main.cpp
#include "TemplateClass.h" // テンプレート実体化の際のステータスに使用 class TestClass { int getValue() { return 100; } }; void main() { // テンプレート実体化 TemplateClass<TestClass> t = new TemplateClass(new TestClass()); // 100が出力される std::cout << t->getValue() << std::endl }
コンパイル時(すなわちコードの自動生成時に)以下のようなリンクエラーが発生する。
error LNK2019: 未解決の外部シンボル "public: int __thiscall TemplateClass
::getValue(void)" (?getValue@?$TemplateClass@VTestClass@@@QAEHXZ) が関数 _wmainで参照されました。
error LNK2019: 未解決の外部シンボル "public: int __thiscall TemplateClass::TemplateClass(class TestClass *)" (??0?$TemplateClass@VTestClass@@@@QAE@PAVTestclass@@@Z) が関数 _wmainで参照されました。
fatal error LNK1120: 外部参照2が未解決です。
VC++がテンプレートについて、inclusion-modelという実体化を採用している為。
inclusion-modelとは、簡単に言うと、テンプレートの実装はヘッダーに書く。
CPPに実装を書いた場合、コンパイラはテンプレートの宣言を実体化できない。
それでもCPPに実装を書きたい場合は、テンプレートの実体をCPPにて明示する。
これを明示的実体化と言う。
明示的実体化の方法
TemplateClass.cpp
#include "TemplateClass.h" #include "TestClass.h" // コンストラクタ TemplateClass<T>::TemplateClass(T* t) { this->t = t; } int TemplateClass<T>::getValue() { t->getValue(); } // 実体化したいクラス(型)を指定する。 template class TemplateClass<TestClass>
これにより、ヘッダーにて実装を晒したくない場合に対応できる。
CPP側で実装し、明示的実体化をしておけば、特定の型以外の実体化を禁止できる。
(特定の型以外の実体化はコンパイル時にリンクエラーとなる)
但し、実体化するクラス(型)が固定されてしまうため、コードの柔軟性は低下する。
また、テンプレートを使用してのメタプログラミングには適用できない。
状況に応じて、ヘッダーで実装するか、明示的実体化を行うか決めるべし。