11

ヘッダー ファイルで関数テンプレートが定義されているとします。#includeここで、このヘッダーに2 つの実装ファイルがあり、それぞれに関数テンプレートへの呼び出しがあるとします。どちらの実装ファイルでも、関数テンプレートは同じ型でインスタンス化されています。

// header.hh
template <typename T>
void f(const T& o)
{
    // ...
}

// impl1.cc
#include "header.hh"

void fimpl1()
{
    f(42);
}

// impl2.cc
#include "header.hh"

void fimpl2()
{
    f(24);
}

リンカが の複数の定義について不平を言うと予想されるかもしれませんf()。具体的にはf()、テンプレートではない場合は、実際にそうです。

  • リンカーが の複数の定義について文句を言わないのはf()なぜですか?
  • リンカーがこの状況を適切に処理しなければならないことが標準で指定されていますか? 言い換えれば、上記のようなプログラムをコンパイルしてリンクすることを常に期待できますか?
  • リンカーが一連の関数テンプレートのインスタンス化を明確にするのに十分なほど賢い場合、インスタンス化された関数テンプレートの場合と同じであるのに、通常の関数に対して同じことができないのはなぜですか?
4

3 に答える 3

5

Gnu C++ コンパイラのマニュアルには、この. 抜粋:

C++ テンプレートは、UNIX システムで通常見られるよりも多くのインテリジェンスを環境から必要とする最初の言語機能です。何らかの方法で、コンパイラとリンカは、各テンプレート インスタンスが必要な場合は実行可能ファイル内で 1 回だけ発生し、それ以外の場合はまったく発生しないようにする必要があります。この問題には、Borland モデルと Cfront モデルと呼ばれる 2 つの基本的なアプローチがあります。

ボーランド モデル

Borland C++ は、共通ブロックに相当するコードをリンカーに追加することで、テンプレートのインスタンス化の問題を解決しました。コンパイラは、それらを使用する各翻訳単位でテンプレート インスタンスを生成し、リンカーはそれらをまとめて折りたたみます。このモデルの利点は、リンカーがオブジェクト ファイル自体のみを考慮する必要があることです。心配する外部の複雑さはありません。この欠点は、テンプレート コードが繰り返しコンパイルされるため、コンパイル時間が長くなることです。このモデル用に書かれたコードは、すべてのテンプレートの定義をヘッダー ファイルに含める傾向があります。

Cフロントモデル

AT&T の C++ トランスレータである Cfront は、テンプレート インスタンスが保存される場所として自動的に維持されるテンプレート リポジトリの概念を作成することで、テンプレートのインスタンス化の問題を解決しました。より新しいバージョンのリポジトリは、次のように機能します。個々のオブジェクト ファイルが構築されると、コンパイラは、見つかったテンプレート定義とインスタンス化をリポジトリに配置します。リンク時に、リンク ラッパーはリポジトリ内のオブジェクトを追加し、以前に発行されなかった必要なインスタンスをコンパイルします。このモデルの利点は、より最適なコンパイル速度と、システム リンカを使用できることです。Borland モデルを実装するには、コンパイラ ベンダーもリンカを置き換える必要があります。欠点は、複雑さが大幅に増加することであり、エラーが発生する可能性があります。一部のコードでは、これは透過的ですが、実際には、1 つのディレクトリに複数のプログラムを構築し、複数のディレクトリに 1 つのプログラムを構築することは非常に困難です。このモデル用に記述されたコードは、非インライン メンバー テンプレートの定義を別のファイルに分離する傾向があり、個別にコンパイルする必要があります。

GNU/Linux や Solaris 2 などの ELF システム、または Microsoft Windows で GNU ld バージョン 2.8 以降を使用する場合、G++ は Borland モデルをサポートします。他のシステムでは、G++ はどちらの自動モデルも実装していません。

于 2008-10-25T05:30:38.500 に答える
5

C++ をサポートするために、リンカはそれらがすべて同じ関数であることを認識し、1 つを除いてすべてをスローするほどスマートです。

編集: 明確化: リンカは関数の内容を比較せず、それらが同じであると判断します。テンプレート化された関数はそのようにマークされ、リンカーはそれらが同じ署名を持っていることを認識します。

于 2008-10-24T23:49:44.007 に答える
1

これは多かれ少なかれ、テンプレートだけの特殊なケースです。

コンパイラは、実際に使用されるテンプレートのインスタンス化のみを生成します。他のソース ファイルから生成されるコードを制御できないため、メソッドが生成されることを確認するために、ファイルごとに 1 回テンプレート コードを生成する必要があります。

これを解決するのは難しいため (標準にはexternテンプレートのキーワードがありますが、g++ はそれを実装していません)、リンカーは単純に複数の定義を受け入れます。

于 2008-10-24T23:57:45.643 に答える