web-dev-qa-db-ja.com

テンプレートの使用時に「未解決の外部シンボル」エラーが発生するのはなぜですか?

テンプレートを使用してクラスのC++コードを記述し、ソース(CPP)ファイルとヘッダー(H)ファイルにコードを分割すると、最終的な実行可能ファイルのリンクに関して、「未解決の外部シンボル」エラーが大量に発生します。オブジェクトファイルが正しく構築され、リンクに含まれているにもかかわらず。ここで何が起きているのですか、どうすれば修正できますか?

90
dlanod

テンプレート化されたクラスと関数は、使用されるまで、通常は別個の.cppファイル(プログラムソースなど)でインスタンス化されません。テンプレートを使用する場合、コンパイラーは、適切なタイプの正しい関数を構築できるように、その関数の完全なコードを必要とします。ただし、この場合、その関数のコードはテンプレートのソースファイルに記載されているため利用できません。

このすべての結果として、コンパイラは、それが他の場所で定義されていると仮定し、テンプレート関数への呼び出しのみを挿入します。テンプレートのソースファイルをコンパイルする場合、プログラムソースで使用されている特定のテンプレートタイプはそこで使用されないため、関数に必要なコードは生成されません。これにより、未解決の外部シンボルが生成されます。

これに利用できるソリューションは次のとおりです。

  1. テンプレートのヘッダーファイルにメンバー関数の完全な定義を含め、テンプレートのソースファイルを持たない、
  2. テンプレートのソースファイル内のすべてのメンバー関数を「インライン」として定義する、または
  3. 「export」キーワードを使用して、テンプレートのソースでメンバー関数を定義します。残念ながら、これは多くのコンパイラでサポートされていません。 (更新: これはC++ 11の時点で標準から削除されました 。)

1と2はどちらも、プログラムソースで型付き関数をビルドしようとするときに、コンパイラがテンプレート関数の完全なコードにアクセスできるようにすることで、基本的に問題に対処します。

109
dlanod

別のオプションは、コードをcppファイルに配置し、同じcppファイルに、使用する予定の型を使用してテンプレートの明示的なインスタンス化を追加することです。これは、事前に知っているいくつかのタイプでのみ使用することがわかっている場合に便利です。

12
shoosh