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側で実装し、明示的実体化をしておけば、特定の型以外の実体化を禁止できる。
(特定の型以外の実体化はコンパイル時にリンクエラーとなる)


但し、実体化するクラス(型)が固定されてしまうため、コードの柔軟性は低下する。
また、テンプレートを使用してのメタプログラミングには適用できない。


状況に応じて、ヘッダーで実装するか、明示的実体化を行うか決めるべし。

参考サイト