0

テンプレート関数を持つクラスBase inがありますbase.h

class Base {
 template <typename T> void test(T a);
}

このテンプレートは読み取りintまたはdouble入力することになっており、クラスBaseから派生したクラスDerivedがあります

クラス Derived で関数 test を呼び出そうとしましたが、リンカ エラーが発生しました。

base.cpp最後に、 の場合、追加することに気付きました

void test(int a);
void test(double a);

コンパイラ エラーは発生しません。この解決策は厄介に思えます。より良い解決策はありますか? ありがとうございました

4

3 に答える 3

3

C++ テンプレートは、それらが使用される同じ変換単位 (.CPP ファイルと含まれるすべてのヘッダー ファイル) で定義する必要があります (完全な関数本体を指定)。ヘッダー ファイルで行ったすべてのことは、(関数の名前と署名を指定して)宣言されています。その結果、 を含めるbase.hと、コンパイラは次のように認識します。

class Base {
  template <typename T> void test(T a);
}

これは関数を宣言しますが、定義しません。それを定義するには、関数本体を含める必要があります。

class Base {
  template <typename T> void test(T a)
  {
    // do something cool with a here
  }
}

これが必要な理由は、C++ コンパイラが「必要に応じて」テンプレートのコードを生成するためです。たとえば、次のように呼び出す場合:

Base obj;
obj.test< int >( 1 );
obj.test< char >( 'c' );

Base::testコンパイラは、テンプレートに基づいて 2 つのマシン コード セットを生成します。1つは 用でint、もう 1 つは 用charです。ここでの制限は、Base::testテンプレートの定義が同じ翻訳単位 (.CPP ファイル) にある必要があることです。そうしないと、コンパイラはBase::test関数の各バージョンのマシン コードをビルドする方法を認識できません。Base::test< T >コンパイラは一度に 1 つの翻訳単位でしか動作しないため、他の CPP ファイルで定義したかどうかはわかりません。手元にあるものでのみ機能します。

これは、C#、Java、および同様の言語でジェネリックが機能する方法とはまったく異なります。個人的には、テンプレートを、必要に応じてコンパイラによって展開されるテキスト マクロと考えるのが好きです。そのため、テンプレート関数の完全な本体を、それが使用されるすべての CPP ファイルに含める必要があることに留意する必要があります。

于 2011-09-29T07:02:45.990 に答える
2

testテンプレート関数は、使用する前に完全に定義する必要があります。これを行う最も簡単な方法は、ヘッダーの関数本体を次のように記述することですbase.h

class Base {
 template <typename T> void test(T a)
 {
    ... function body here
 }
}
于 2011-09-29T06:30:40.123 に答える
0

基本クラスでテンプレート関数を宣言する場合、つまりコンパイル時にテンプレート引数を取りますが、実行時の実装である派生クラスを介してアクセスしようとすると、実行時に提供できないコンパイル時のテンプレート要求、および主なものc ++これをサポートしていません。

于 2012-10-19T11:36:12.167 に答える