web-dev-qa-db-ja.com

C ++テンプレート、リンクエラー

持っているテンプレートクラスの呼び出しに問題があります。テンプレートである新しい型名Arrayを宣言しました。

.hppファイル内:

template <typename T>
class Array
{
public:
   Array();
};

.cppファイル:

template <typename T>
Array<T>::Array()
{
//Do something
}

主に:

Array<int> arr;

リンケージエラーが発生します:ctorへの未解決の外部シンボル。

何か案が?

35
Boris Raznikov

メンバー関数を含むテンプレート関数は、すべてヘッダーファイルに記述する必要があります。つまり、テンプレートクラスがある場合、その実装は完全にヘッダーファイルになければなりません。これは、テンプレートのインスタンス化ごとにコードを生成するために、コンパイラーが(署名だけでなく)テンプレート定義全体にアクセスできる必要があるためです。

67
Tyler McHenry

テンプレート宣言とテンプレート関数定義の両方をヘッダーファイルに入れます。ほとんどのC++コンパイラは、テンプレート用の個別のコンパイルモデルを簡単にサポートしていません。

9
anon

テンプレート化された関数の定義が使用されている場所に表示されない場合(つまり、ヘッダーまたは同じCPPファイルにない場合)、 作成するインスタンス化をコンパイラーに指示する にする必要があります。

6
moonshadow

ここでの問題は、.cppファイルでコンストラクターの定義を非表示にしていることです。この定義はallタイプTに適用されます。これには、使用するTとしてintが含まれますが、宣言のみであるため、実際には定義は提供されません。
リンカはシンボルArray<int>::Array()を見つけることができません。

これで、次のような行を追加できます。

Array<int> arr1;

array.cppファイルの最後に配置すると、コンパイラはinstantiateリンカーが探している正しい定義になります。ただし、これはone定義、Array<int>の定義のみを提供し、その他は提供しません。

このソリューションは、別のテンプレートパラメータのArray、たとえばdoubleが必要になるまで機能します。その時点で、次のものを追加する必要があります。

Array<double> arr2;

あなたのArray.cppファイルの終わりまで-これで、これが持続不可能であることがわかります!

C++で将来必要なany型を処理する必要がある場合は、今度はctor(およびおそらく他のすべてのメンバー関数)の定義をヘッダー(および何も残っていないので、.cppファイルを削除します。

5
quamrana

上記のように、C++のテンプレートでは、新しいメソッドのプロセスがコンパイル時にコンパイラーによって実行されます。問題は、その間にthmのすべての定義を知る必要があるため、すべてのクラス/関数宣言がar hまたはhppである必要がありますファイル。

1
Boris Raznikov

別の答えは、(メインではなく).cppファイルのみをコンパイルし、オブジェクトファイルのサイズを確認してからempty.cppファイルを作成してから、そのempty.cppをコンパイルします。最後に、両方のオブジェクトファイルのサイズを比較します。それらのサイズが同じであることがわかります。つまり、.cppファイルはコンパイラーにとって何の役にも立たないため、リンカーは何も見つけることができません。

1
mert inan