2011-03-03 11 views
2

可能性の重複:
Why should the implementation and the declaration of a template class be in the same header file?C++のテンプレート定義をヘッダーに含める必要があるのはなぜですか?

例えばクラスメソッドの実装は、ヘッダーにする必要がない理由テンプレートクラスを定義するとき?実装ファイル(cpp/cxx)に含まれないのはなぜですか?

+4

これは私がどの質問をしているのか正確には分かっていません:) –

+2

私はそのような質問を見つけることができませんでした... – EricSchaefer

+2

彼らは、あなたがたいていそうしたくないのです。 –

答えて

12

テンプレートクラスはクラスではなく、クラスを作成するために使用できるテンプレートです。このようなクラスをインスタンス化すると、たとえば次のようになります。 MyTemplate<int>、コンパイラはその場にクラスを作成します。テンプレートを作成するには、テンプレートを使用して(テンプレートを使用してMyTemplate<int>::foo()などの実際のメンバー関数を作成できるように)すべてのテンプレートメンバー関数を表示する必要があります。したがって、これらのテンプレートメンバー関数はヘッダーに存在する必要があります。

メンバーがヘッダーにない場合、コンパイラーは単にそれらが他の場所に存在するとみなし、テンプレート関数の宣言から実際の関数宣言を作成するだけで、リンカーのエラーが発生します。

"export"キーワードはこれを修正することになっていますが、それをサポートするコンパイラはほとんどありません(私はComeauのみ知っています)。

MyTemplate<int>を明示的にインスタンシエートすることもできます。コンパイラは、のメンバー関数定義テンプレートを含むcppファイルをコンパイルすると、MyTemplate<int>の実際のメンバー関数を作成します。

+2

"テンプレートクラスはクラスではありません" - これは、質問のように "テンプレートクラス"ではなく "クラステンプレート"と呼ぶべきです。 –

+0

OKです。 – EricSchaefer

+0

'export'キーワードはベンダーだけがサポートしています(私はいくつかの癖があると思います)。その同じベンダーは、今後の標準からそれを削除することを要求しました。これは、その言語には存在しないと言っているほどです。 –

4

これらは、インスタンス化されるときにコンパイラに表示される必要があります。つまり、ヘッダーにテンプレートを公開する場合、暗黙的なインスタンス化に依存する場合は、そのヘッダーを含むすべての翻訳単位で定義を表示する必要があります。

テンプレートを明示的にインスタンス化する場合はヘッダーに定義する必要はありませんが、ほとんどの場合はこれが良い考えではありません。

理由としては、基本的には、コンパイラが定義を解析するときにテンプレートがコンパイルされず、インスタンス化された後に特定のインスタンス化タイプ用にコンパイルされるということです。

+0

しかし、なぜですか? (7文字以上) – EricSchaefer

+0

@EricSchaefer:答えを編集しました。なぜなら、テンプレートは解析時にコンパイルされず、インスタンス化されるからです。 –

2

コンパイラがexportをサポートしている場合、それはサポートされていません。 EDGベースのコンパイラのみがexportをサポートしており、そのためにC++ 0xから削除されます。

エクスポートされていないテンプレートでは、引数として指定した特定の型に対してインスタンス化するために、完全なテンプレート定義が表示される必要があります。たとえば:あなたは、いくつかの翻訳単位でX<float>(5)を書くとき

template<typename T> 
struct X { 
    T t; 
    X(int i): t(i) {} 
}; 

は今、その翻訳単位をコンパイルするの一環として、コンパイラは、Xのコンストラクタは、正しい型そのためのコードを生成していることを確認する必要があります等々。したがって、Xの定義を参照して、X<float>(5)を許可することができますが、X<char*>(5)を禁止する必要があります。

コンパイラが同じテンプレート定義を使用するすべての翻訳単位で確実に確認できる唯一の賢明な方法は、定義をヘッダファイルに入れることです。しかし、標準に関しては、手動でコピーアンドペーストするか、その1つの翻訳単位でのみ使用されるテンプレートをcppファイルに定義することを歓迎します。効果で

exportは、それがオブジェクトファイルの特別な種類に出力テンプレート定義の解析された形をしなければならないコンパイラに指示します。その後、リンカはテンプレートのインスタンス化を実行します。通常のツールチェーンでは、コンパイラはテンプレートのインスタンス化を実行するのに十分スマートであり、リンカーはそうではありません。テンプレートのインスタンス化では、すべての基本構文解析を超えて行う必要があることに注意してください。

0

これらはCPPファイルに入れることができます。

問題は、翻訳単位ごとにテンプレートクラス(例:std :: vector < int>など)の特定のインスタンス化のためのコードをコンパイラが作成することから発生します。 CPPファイルで関数を定義する際の問題は、そのCPPファイル内のすべての可能なフォームを定義する必要があることです(これはテンプレートの特殊化と呼ばれます)。あなたは専門を使用してint型の場合のCPPファイルで関数を定義することができ、上記

は、だから、int型のベクトルをexampled。もちろん

例えば

template<> void std::vector<int>::push_back(int& intVal) 

これは、特定の場合のための最適化の利点を生成することができますが、それは肥大化は、STLによって導入することができるどれだけのコードあなたのアイデアを与えるんやって!

0

このテンプレートの側面は、How does C++ link template instancesという件名のインスタンス化メカニズムと混同しないように、コンパイルモデルと呼ばれています。

インスタンス生成メカニズムは、質問への答えは、「インスタンス化が発生した?」、インスタンス化モデルが答えである「ソースが発見されたどこ?」

両規格のコンパイルモデルがありますとどこかの定義を配置することができます

  • 含め、定義が使用可能でなければなりませんあなたが知っている1、分離

  • 、キーワードexportの助けを借りてください。これは標準から削除されており、C++ 0Xでは利用できません。削除の理由の1つは、広く実装されていないということでした(1つの実装のみ)。

参照C++テンプレートの詳細については、デビッドVandevoordeとニコライJosuttis氏やhttp://www.bourguet.org/v2/cpplang/export.pdfによって完全ガイド、それ以降の論文の主題であること分離コンパイルモデル。

関連する問題