テンプレートクラスの「特殊化」と「明示的インスタンス生成」を同時に使う場合は注意が必要だ(2)
先日の記事で扱った問題の対処法について.結論:テンプレートクラスの(部分)特殊化を行う場合は,そのテンプレートクラスを宣言しているヘッダファイルで「(部分)特殊化の宣言」を行うこと.部分特殊化の実装は,通常のクラスまたはメンバ関数の実装と同様にすること(inline 関数やテンプレート関数ならその場で実装,そうでないならユニットの実装ファイルに実装を記述し,実装が複数のオブジェクトファイルで重複しないようにする).
先日の記事の例の場合, unit1.h を以下のように変更する:
/*! \file unit1.h \date Feb.19, 2009 */ #ifndef unit1_h #define unit1_h #include <iostream> namespace hogehoge { template <typename T> struct TTest { T x; void print (void) const; }; // 追加: // declaration of specialization (特殊化の宣言) template <> void TTest<int>::print (void) const; } // end of namespace hogehoge #endif // unit1_h
ここで追加された部分特殊化の宣言により,このヘッダを include するソースでは TTest<T>::print が T=int に対して部分特殊化されていることを知ることができる.この特殊化された関数は unit1.o でしか定義されていないから,リンカは確実に unit1.o をリンクするようになり,先日の記事のような問題は生じない.
なお, unit1.h に TTest<int>::print の実装を書くと,複数のオブジェクトファイルで TTest<int>::print が定義されることになり,リンカが重複定義エラーを吐くので注意されたい.もちろんこの関数が inline 関数であれば,ここに定義を書けばよい.
g++ -Wall unit1.cpp -c ar r unit1.a unit1.o g++ -Wall unit2.cpp -c g++ -Wall main2.cpp -c g++ -Wall unit2.o main2.o unit1.a
して実行すると:
x is hoge x= 0xa x is 2.5
のように,期待通りの結果が得られる.