以前の投稿 ( http://qiita.com/MasayaMizuhara/items/37f8c2a5462a4f7f8ea0 ) の補足。
以前の投稿で行ったテンプレートの宣言と実装を分離する方法は、 非明示的インスタンス化 と呼ばれる。非明示的インスタンス化には実装の詳細を隔離できるというメリットがある一方で、
- オブジェクトファイルのサイズが大きくなる
- コンパイルやリンクに時間がかかる
- ( Utility.hの最終行の ) #includeによりAPIの結合度があがる
といったデメリットもある。上記問題を解決する方法として、 明示的インスタンス化 と呼ばれる方法がある。明示的インスタンス化による、テンプレートの宣言と実装を分離するサンプルを下記に示す。
Utility.h : テンプレート関数の宣言のみ記述したファイル
// Utility.h
#pragma once
#include <string>
template<typename T>
class Utility
{
public:
std::string toString(const T & value);
};
Utility.cpp : Utility.hの実装ファイル
// Utility.cpp
#include "Utility.h"
#include <sstream>
template<typename T>
std::string Utility<T>::toString(const T & value)
{
std::stringstream ss;
ss << value;
return ss.str();
}
// 明示的テンプレートのインスタンス化
template class Utility<int>;
main.cpp : Utilityクラスの使用法を説明するためのファイル
// main.cpp
#include <iostream>
#include "Utility.h"
int main()
{
Utility<int> utility;
std::cout << utility.toString(20) << std::endl;
return 0;
}
明示的インスタンス化には非明示的インスタンス化の持つ問題を解決できるメリットがあるが、
- テンプレートの明示的インスタンス化を予め行わなくてはならない
というデメリット ( ? ) がある ( 上記の例では、Utility.cppの最終行でインスタンス化した型 ( int ) 以外のUtilityインスタンスを作成できない ) 。
結論
明示的にインスタンス化する型が決まっている、またはユーザが自由にインスタンス化を行うことを許可したくない場合は明示的インスタンス化、そうでない場合は非明示的インスタンス化により宣言と実装の分離を行うのが良いと思う。