[c++]テンプレート関数の定義と実装はまとめてヘッダファイルに書かなければいけない
(備忘録です.もっとうまいやり方があったら教えてください...)
関数の定義は「ヘッダファイル」,実装は「cppファイル」に記述するというような場合が結構あると思います.
しかし,テンプレート関数の場合,定義と実装は「ヘッダファイル」と「cppファイル」に分離できないようです.
ダメな例
hoge.h
class Hoge{
public:
template <class T> void func1(T val);
};
hoge.cpp
#include <iostream>
#include "hoge.h"
template <class T>
void Hoge::func1(T val){
std::cout << "func1" << std::endl;
}
main.cpp
#include "hoge.h"
int main(){
Hoge h;
h.func1(1);
h.func1("test");
}
結果
$ g++ -o hoge.exe hoge.cpp main.cpp
main.cpp: In function ‘int main()’:
main.cpp:5: error: no matching function for call to ‘Hoge::func1()’
と出る.
解決策
ヘッダに実装も書く.
一応,定義とは分離させて以下のように書いた.
hoge.h
#include <iostream>
class Hoge{
public:
template <class T> void func1(T val);
};
template <class T>
void Hoge::func1(T val){
std::cout << "func1" << std::endl;
}
main.cpp
#include "hoge.h"
int main(){
Hoge h;
h.func1(1);
h.func1("test");
}
結果
$ g++ -o hoge.exe main.cpp
$ ./hoge.exe
func1
func1
明示的実体化による解決
テンプレートの実装をヘッダに書かなければならない理由 - (void*)Pないと: http://d.hatena.ne.jp/pknight/20090826/1251303641
によると,
コンパイルの時点でテンプレート関数が一回も実体化されていないのが問題らしい.
そこで予め使われる型を使って実体化しておくと実行できる.
hoge.h
class Hoge{
public:
template <class T> void func1(T val);
};
hoge.cpp
#include <iostream>
#include "hoge.h"
template void Hoge::func1(int val);
template void Hoge::func1(char const* val);
template <class T> void Hoge::func1(T val){
std::cout << "func1" << std::endl;
}
main.cpp
#include "hoge.h"
int main(){
Hoge h;
h.func1(1);
h.func1("test");
}
結果
$ g++ -o hoge.exe hoge.cpp main.cpp
$ ./hoge.exe
func1
func1
しかし,明示的実体化は予め使われる型の関数宣言が必要なので,新しい型(特にユーザ定義型)が追加される場合は対応できない!