web-dev-qa-db-ja.com

C ++テンプレートとヘッダーファイル

そのため、C++テンプレートをヘッダー(.h)ファイルとソース(.cpp)ファイルに分離すべきではないと聞いた。

たとえば、次のようなテンプレート:

template <class T>
class J
{   
   T something;
};

これは本当ですか?なぜそうですか?

そのために宣言と実装の両方を同じファイルに配置する必要がある場合、.hファイルまたは.cppファイルに配置する必要がありますか?

27
kamikaze_pilot

ヘッダー。

テンプレートは、リンク時ではなくコンパイル時にインスタンス化され、異なる翻訳単位(.cppファイル)リンク時にのみお互いを「知っている」。ヘッダーは、コンパイル時に広く「知られている」傾向があります。なぜなら、#includeそれらを必要とする任意の翻訳単位で。

詳しくは https://isocpp.org/wiki/faq/templates をご覧ください。

テンプレートクラスを.cppファイルに配置できない理由は、.cppファイルを「コンパイル」するために、Tの代わりに使用されているタイプを知る必要があるためです。クラスJ)のように、コンパイルするのに十分な情報がありません。したがって、すべてヘッダーに含まれている必要があります。

実装をクリーンにするために別のファイルに分割する場合、ベストプラクティスは.hxxファイルを使用することです。このように:ヘッダーファイルJ.h内に、次を入力します。

#ifndef _J_H__
#define _J_H__

template <class T> class J{  // member definitions };

#include "j.hxx"

#endif // _J_H__

そして、j.hxxでは

template <class T> J<T>::J() { // constructor implementation }

template <class T> J<T>::~J() { // destructor implementation }

template <class T> void J<T>::memberFunc() { // memberFunc implementation }

// etc.

最後に、テンプレートクラスを使用する.cppファイルで、K.cppという名前を付けます。

#include "J.h" // note that this always automatically includes J.hxx    
void f(void)
{
     J<double> jinstance;  // now the compiler knows what the exact type is.
}
14
Chris A.

はい、それは本当だ。宣言と実装は通常、ヘッダーファイルにまとめて配置されます。一部のコンパイラは、それらを分離できるexportキーワードを試しましたが、C++ 0xから削除されました。 this FAQ entry すべての汚れた詳細について確認してください。

4
jonsca

テンプレートコードを他の翻訳単位(.cppファイル)で使用できるようにする必要がある場合は、実装を.hファイルに配置する必要があります。そうしないと、他のユニットはテンプレートをインスタンス化できません(使用するタイプ)。

テンプレート関数が1つの.cppファイルでのみインスタンス化される場合、そこで定義できます。これは、クラスがテンプレートであるプライベートメンバー関数を持つ場合に発生します(クラスヘッダーファイルではなく実装ファイルからのみ呼び出されます)。

2
John Zwinck