ここで、CPP ファイルでテンプレート関数を定義したとしましょう。これは、別の翻訳単位で終了することを意味します。簡単な例を次に示します。
ヘッダー、example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
template<int TValue>
class example
{
public:
int get_tvalue();
};
#endif
ソース ファイル、example.cpp
#include "example.h"
template<int TValue>
int example<TValue>::get_tvalue()
{
return TValue;
}
もう 1 つのソース ファイル、main.cpp
#include "example.h"
int main()
{
example<5> instance;
instance.get_tvalue();
return 0;
}
GCC を使用してこれらをまとめてコンパイルすると、undefined reference to 'example<5>::get_tvalue()'
. これは、テンプレート クラスがインスタンス化される方法によるものです。テンプレートクラスの定義はまさに... テンプレートであり、実際のクラスではありません。実際のクラス定義は、そのクラスのパラメーター化された (具体的には、完全に特殊化された) 定義が発生したときに作成されます。この場合はexample<5>
. その完全に特殊化されたクラス定義は main.cpp にのみ存在します... example.cpp 内にそのようなクラスはありません! Example.cpp にはテンプレートのみが含まれ、特殊化は含まれていません。これは、関数が main.cpp でget_tvalue
定義されていないことを意味するため、エラーが発生します。example<5>
これは、2 つの方法のいずれかで修正できます。最初の方法は、テンプレート クラス全体を常にヘッダー ファイルで定義することです。これは、たとえば STL コンテナーで行われる方法です。別の方法は、example.cpp でパラメータ化されたクラスの作成を強制することです...追加することでこれを行うことができます
template class example<5>;
example.cpp の最後まで。example.cpp には実際のクラス定義があるため、コンパイル ステップの最後に変換ユニット main.o と example.o がリンクされると、 andexample<5>
の実際の関数定義も得られます。example<5>::get_tvalue
明らかに、ほとんどの場合、これは不適切なアプローチですが、テンプレート パラメーターが小さな範囲の値しかとらない状況では機能します。ただし、クラス全体をヘッダー ファイルに配置するのが、おそらく最も簡単で、最も安全で、最も柔軟です。