なぜテンプレートクラスとテンプレートメンバー関数はファイルに分けて書けないのか(.hと.cpp)
3503 ワード
クラスを定義するには、一般的にヘッダファイルでクラス宣言を行い、cppファイルで実装されますが、テンプレートを使用する場合は、現在のC++コンパイラがコンパイルを分離できないことに注意してください.実装コードと宣言コードをヘッダファイルに配置することが望ましいです.次のようになります.
ここだcppの内容はtestに置くべきである.hで、そうでないと最終実行可能プログラムの生成時にエラーが発生します(リンク時にエラーが発生します).コンパイル時にテンプレートは真のバイナリコードを生成することはできないため、テンプレートクラスまたは関数を呼び出すCPPファイルをコンパイルするときに対応するテンプレート宣言と実装を探すことができる.この場合、コンパイラはテンプレートクラスまたは関数を実装するCPPファイルの存在を知らないため、テンプレートクラスまたは関数の宣言しか見つからず実装が見つからない.リンクプログラムにアドレスを探すためにシンボルを作成するしかありません.しかし、テンプレートクラスや関数の実装はバイナリコードにコンパイルされず、リンクプログラムがアドレスを見つけられず、エラーを報告するしかなかった.「C++プログラミング思想」第15章(300ページ)は、テンプレート定義が特殊である理由を説明している.templateによって処理されるものは、コンパイラがテンプレートインスタンスに通知されるまで待機状態にあることを意味します.コンパイラとコネクタのいずれかで、指定したテンプレートの多重定義を削除するメカニズムがあります.したがって、使いやすいように、ほとんどの場合、テンプレート宣言と定義をヘッダファイルに配置します.
テクニック15:テンプレート定義の場所はどこですか?はい.cppファイルですか?
通常、あなたはいます.hファイルに関数とクラスを宣言し、それらの定義を個別に配置する.cppファイルにあります.しかし、テンプレートを使用する場合、コンパイラは、その宣言だけでなく、テンプレートをインスタンス化するときにテンプレートの正確な定義を見る必要があるため、このような習慣的な方法は役に立たなくなります.したがって、テンプレートの宣言と定義を同じにすることが最善の方法である.hファイルにあります.これが、すべてのSTLヘッダファイルにテンプレート定義が含まれている理由です.
もう一つの方法はキーワード「export」を使うことです!あなたはいてもいいです.hファイルでは、テンプレートクラスとテンプレート関数を宣言します.はい.cppファイルでは、キーワードexportを使用して、特定のテンプレートクラスオブジェクトとテンプレート関数を定義します.その後、他のユーザーコードファイルに宣言ヘッダファイルを含めると、これらのオブジェクトと関数を使用できます.例:
ある程度、これは、別のコードファイルなどの他のコンパイルユニットの通常のタイプの変数やオブジェクトにアクセスするために使用されるキーワードexternに似ています.しかし、ここでは、すべてのコンパイラがexportキーワードをサポートしているわけではありません.(私たちが最もよく知っている、最もよく使われている2つのコンパイラVSとGCCはexportをサポートしていない典型的な代表です).このような不確定に対して、最善の方法は解決策の1つを採用することです.宣言定義を一緒に置くことです.これはある程度C++プログラミングの優雅性を破壊しますが.
スプリットコンパイルモード(Separate Compilation Model)では、ある翻訳ユニット(Translation Unit)で関数、タイプ、クラスオブジェクトなどを定義し、別の翻訳ユニットで参照することができます.コンパイラ(Compiler)は、すべての翻訳ユニットを処理した後、チェーンコネクタ(Linker)次に、externシンボルへのすべての参照を処理し、単一の実行可能ファイルを生成する.このモードにより、C++コードが気に入って優雅に記述される.
しかし、このモードはテンプレートに馴染まない.(Template).標準では、コンパイラはテンプレートをインスタンス化するときに定義エンティティをコンテキストで表示する必要があります.逆に、テンプレートをインスタンス化する前に、コンパイラはテンプレートの定義体を処理しません.理由は簡単ですが、コンパイラはtypenameの実パラメータが何であるかを事前に知っていますか.そのため、テンプレートのインスタンス化と定義体は同じに戻さなければなりません.翻訳ユニットにあります.
優雅さで知られるC++は、この「負け犬」が生きていることを許せない.標準C++はこのために「テンプレート分離コンパイルモード(Separation Model)」およびexportキーワードを制定した.しかしtemplateの意味自体の特殊性によりexportは表現時に性能が劣っている.コンパイラは.netとjavaが行ったようにテンプレートエンティティに「中間擬似コード(IPC,intermediate pseudo-code)」を生成せざるを得ない他の翻訳ユニットがインスタンス化時に定義体を見つけることができるようにする.インスタンス化に遭遇した場合、指定したtypenameインスタンスに基づいてこのIPCを再コンパイルし、「コンパイルを分離」する目的を達成します.そのため、この基準はほとんどの有名なコンパイラベンダーから強くボイコットされています.誰がexportをサポートしますか?Comeau C/C++とIntel 7.xコンパイラサポート.「ISO 100%支持」で知られるVSとGCCは無視している.この2大コンパイラの「100%サポート」はどのバージョンのISOなのか本当に分かりません.VS 2008では、exportキーワードはIDEに青で表示され、VS IDEがそれを認識していることを示しているが、コンパイル時には「このキーワードをサポートしていない」と警告友情で提示され、セットのMSDN 9のC++keywordsページではこのキーワードはまったく調べられない.VS 2010では、そんなに遠慮しないで、IDEでは青を表記していますが、はっきりと間違っています.C++11はキーワードexportの使用をキャンセルしました.参考文献クリックでリンクを開くクリックでリンクを開く
test.h
template
class CTest
{
public:
T& GetValue();
void SetValue(const T& _Value);
protected:
T m_Value;
};
test.cpp
template
T& CTest::GetValue()
{
return m_Value;
}
template
void CTest::SetValue(const T& _Value)
{
m_Value = _Value;
}
ここだcppの内容はtestに置くべきである.hで、そうでないと最終実行可能プログラムの生成時にエラーが発生します(リンク時にエラーが発生します).コンパイル時にテンプレートは真のバイナリコードを生成することはできないため、テンプレートクラスまたは関数を呼び出すCPPファイルをコンパイルするときに対応するテンプレート宣言と実装を探すことができる.この場合、コンパイラはテンプレートクラスまたは関数を実装するCPPファイルの存在を知らないため、テンプレートクラスまたは関数の宣言しか見つからず実装が見つからない.リンクプログラムにアドレスを探すためにシンボルを作成するしかありません.しかし、テンプレートクラスや関数の実装はバイナリコードにコンパイルされず、リンクプログラムがアドレスを見つけられず、エラーを報告するしかなかった.「C++プログラミング思想」第15章(300ページ)は、テンプレート定義が特殊である理由を説明している.templateによって処理されるものは、コンパイラがテンプレートインスタンスに通知されるまで待機状態にあることを意味します.コンパイラとコネクタのいずれかで、指定したテンプレートの多重定義を削除するメカニズムがあります.したがって、使いやすいように、ほとんどの場合、テンプレート宣言と定義をヘッダファイルに配置します.
テクニック15:テンプレート定義の場所はどこですか?はい.cppファイルですか?
通常、あなたはいます.hファイルに関数とクラスを宣言し、それらの定義を個別に配置する.cppファイルにあります.しかし、テンプレートを使用する場合、コンパイラは、その宣言だけでなく、テンプレートをインスタンス化するときにテンプレートの正確な定義を見る必要があるため、このような習慣的な方法は役に立たなくなります.したがって、テンプレートの宣言と定義を同じにすることが最善の方法である.hファイルにあります.これが、すべてのSTLヘッダファイルにテンプレート定義が含まれている理由です.
もう一つの方法はキーワード「export」を使うことです!あなたはいてもいいです.hファイルでは、テンプレートクラスとテンプレート関数を宣言します.はい.cppファイルでは、キーワードexportを使用して、特定のテンプレートクラスオブジェクトとテンプレート関数を定義します.その後、他のユーザーコードファイルに宣言ヘッダファイルを含めると、これらのオブジェクトと関数を使用できます.例:
// output.h -
template void output (const T& t);
// out.cpp -
#include
export template void output (const T& t) {std::cerr << t;}
//main.cpp:
#include "output.h"
void main() // output()
{
output(4);
output("Hello");
}
ある程度、これは、別のコードファイルなどの他のコンパイルユニットの通常のタイプの変数やオブジェクトにアクセスするために使用されるキーワードexternに似ています.しかし、ここでは、すべてのコンパイラがexportキーワードをサポートしているわけではありません.(私たちが最もよく知っている、最もよく使われている2つのコンパイラVSとGCCはexportをサポートしていない典型的な代表です).このような不確定に対して、最善の方法は解決策の1つを採用することです.宣言定義を一緒に置くことです.これはある程度C++プログラミングの優雅性を破壊しますが.
スプリットコンパイルモード(Separate Compilation Model)では、ある翻訳ユニット(Translation Unit)で関数、タイプ、クラスオブジェクトなどを定義し、別の翻訳ユニットで参照することができます.コンパイラ(Compiler)は、すべての翻訳ユニットを処理した後、チェーンコネクタ(Linker)次に、externシンボルへのすべての参照を処理し、単一の実行可能ファイルを生成する.このモードにより、C++コードが気に入って優雅に記述される.
しかし、このモードはテンプレートに馴染まない.(Template).標準では、コンパイラはテンプレートをインスタンス化するときに定義エンティティをコンテキストで表示する必要があります.逆に、テンプレートをインスタンス化する前に、コンパイラはテンプレートの定義体を処理しません.理由は簡単ですが、コンパイラはtypenameの実パラメータが何であるかを事前に知っていますか.そのため、テンプレートのインスタンス化と定義体は同じに戻さなければなりません.翻訳ユニットにあります.
優雅さで知られるC++は、この「負け犬」が生きていることを許せない.標準C++はこのために「テンプレート分離コンパイルモード(Separation Model)」およびexportキーワードを制定した.しかしtemplateの意味自体の特殊性によりexportは表現時に性能が劣っている.コンパイラは.netとjavaが行ったようにテンプレートエンティティに「中間擬似コード(IPC,intermediate pseudo-code)」を生成せざるを得ない他の翻訳ユニットがインスタンス化時に定義体を見つけることができるようにする.インスタンス化に遭遇した場合、指定したtypenameインスタンスに基づいてこのIPCを再コンパイルし、「コンパイルを分離」する目的を達成します.そのため、この基準はほとんどの有名なコンパイラベンダーから強くボイコットされています.誰がexportをサポートしますか?Comeau C/C++とIntel 7.xコンパイラサポート.「ISO 100%支持」で知られるVSとGCCは無視している.この2大コンパイラの「100%サポート」はどのバージョンのISOなのか本当に分かりません.VS 2008では、exportキーワードはIDEに青で表示され、VS IDEがそれを認識していることを示しているが、コンパイル時には「このキーワードをサポートしていない」と警告友情で提示され、セットのMSDN 9のC++keywordsページではこのキーワードはまったく調べられない.VS 2010では、そんなに遠慮しないで、IDEでは青を表記していますが、はっきりと間違っています.C++11はキーワードexportの使用をキャンセルしました.参考文献クリックでリンクを開くクリックでリンクを開く