コンパイラには、インスタンスの配置とリンケージの方法として、外部、静的、大域、明示的、半明示的のどれを使うかを指定できます。
外部インスタンスはすべての開発に適しており、テンプレートのコンパイルとしては総合的に最も優れています。
静的インスタンスは非常に小さなプログラムやデバッグに適しており、用途は限られています。
大域インスタンスは、ある種のライブラリ構造に適しています。
明示的インスタンスは、厳密に管理されたアプリケーションコンパイル環境に適しています。
半明示的インスタンスは、それより多少管理の程度が緩やかなアプリケーションコンパイル環境に適しています。ただし、このインスタンスは明示的インスタンスより大きなオブジェクトファイルを生成し、用途は限られています。
特別な理由がない限り、デフォルトの外部インスタンス方式を使用してください。詳細は、『C++ プログラミングガイド』を参照してください。
外部インスタンスの場合では、すべてのインスタンスがテンプレートレポジトリ内に置かれます。テンプレートインスタンスは 1 つしか存在できません。つまり、インスタンスが未定義であるとか、重複して定義されているということはありません。テンプレートは必要な場合にのみ再インスタンス化されます。
テンプレートインスタンスは、レポジトリ内では大域リンケージを受け取ります。インスタンスは、外部リンケージで現在のコンパイル単位から参照されます。
外部リンケージは、-instances=extern オプションで指定します。このオプションはデフォルトです。
インスタンスはテンプレートレポジトリ内に保存されているので、外部インスタンスを使用する C++ オブジェクトをプログラムにリンクするには CC コマンドを使用しなければなりません。
使用するすべてのテンプレートインスタンスを含むライブラリを作成したい場合には、CC コマンドに -xar オプションを指定してください。ar コマンドは使用できません。次に例を示します。
%demo CC -xar -o libmain.a a.o b.o c.o
詳細は、第 6 章「ライブラリの構築」を参照してください。
静的インスタンスの場合は、すべてのインスタンスが現在のコンパイル単位内に置かれます。その結果、テンプレートは各再コンパイル作業中に再インスタンス化されます。インスタンスはテンプレートレポジトリに保存されません。
インスタンスは静的リンケージを受け取ります。これらのインスタンスは、現在のコンパイル単位以外では認識することも使用することもできません。そのため、テンプレートの同じインスタンス化がいくつかのオブジェクトファイルに存在することがあります。これには、次の欠点があります。
複数のインスタンスによって不必要に大きなプログラムが生成されます (したがって、静的インスタンスのリンケージは、テンプレートがインスタンス化される回数が少ない小さなプログラムだけに適しています)。
静的変数を持つテンプレートにはその変数のコピーがたくさんあります。これは必然的に C++ 標準に違反することになります。したがって、静的インスタンスはテンプレート内の静的変数には使用できません。
静的インスタンスは潜在的にコンパイル速度が速いため、修正継続機能を使用したデバッグにも適しています (『dbx コマンドによるデバッグ』を参照してください)。
静的インスタンスリンケージは、-instances=static コンパイルオプションで指定します。静的インスタンスリンケージは、定義取り込み型テンプレート編成 (テンプレートを使用するファイルの中にテンプレートの宣言と定義が含まれている編成) でのみ使用することができます。コンパイラは定義を検索しません (『C++ プログラミングガイド』を参照してください)。
大域インスタンスの場合では、すべてのインスタンスが現在のコンパイル単位の中に置かれます。その結果、テンプレートは各再コンパイル作業中に再インスタンス化されます。テンプレートはテンプレートデータベースに保存されません。
テンプレートインスタンスは大域リンケージを受け取ります。これらのインスタンスは現在のコンパイル単位以外でも認識したり、使用したりできます。その結果、複数のコンパイル単位におけるインスタンス化でリンク作業中に複数のシンボル定義のエラーが生じることがあります。したがって、大域インスタンスは、インスタンスが繰り返されないことがわかっている場合に限り適しています。
大域インスタンスは、-instances=global オプションで指定します。
大域インスタンスは、定義取り込み型テンプレート編成でのみ使用することができます。コンパイラは定義を検索しません。
明示的インスタンスの場合、インスタンスは、明示的にインスタンス化されたテンプレートに対してのみ生成されます。暗黙的なインスタンス化は行われません。インスタンスは現在のコンパイル単位内に置かれるため、テンプレートは再コンパイルのたびに再インスタンス化され、テンプレートレポジトリには保存されません。
テンプレートインスタンスは大域リンケージを受け取ります。これらのインスタンスは、現在のコンパイル単位の外でも認識でき、使用できます。同じプログラムで複数の明示的なインスタンス化があると、リンカーで複数シンボル定義エラーになります。したがって、明示的インスタンス方式は、明示的なインスタンス化でライブラリを構成する場合のように、インスタンスが繰り返されないことがわかっている場合に限り適しています。
明示的インスタンスは、-instances=explicit オプションで指定します。
明示的インスタンスリンケージは、定義取り込み型テンプレート編成でのみ使用できます。コンパイラは定義を検索しません。
半明示的インスタンスの場合、インスタンスは、明示的にインスタンス化されるテンプレートやテンプレート本体の中で暗黙的にインスタンス化されるテンプレートに対してのみ生成されます。main コード行内で行う暗黙的なインスタンス化は不完全になります。インスタンスは現在のコンパイル単位に置かれます。したがって、テンプレートは再コンパイルごとに再インスタンス化され、テンプレートレポジトリには保存されません。
明示的インスタンスは大域リンケージを受け取ります。これらのインスタンスは、現在のコンパイル単位の外でも認識でき、使用できます。同じプログラムで複数の明示的インスタンス化があると、リンカーで複数のシンボル定義エラーになります。したがって、半明示的インスタンスは、明示的なインスタンス化によってライブラリを構成する場合のように、明示的インスタンスが繰り返されないことがわかっている場合にだけ適しています。
明示的インスタンスの本体内から使用される暗黙的インスタンスは、静的リンケージを受け取ります。これらのインスタンスは現在のコンパイル単位の外では認識できません。そのため、テンプレートの同じインスタンス化がいくつかのオブジェクトファイルに存在することがあります。これには、次の 2 つの欠点があります。
複数のインスタンスによって不必要に大きなプログラムが生成されます (したがって、半明示的インスタンスのリンケージは、テンプレート本体で複数のインスタンス化が起こらないプログラムだけに適しています)。
静的変数を持つテンプレートにはその変数のコピーがたくさんあります。これは必然的に C++ 標準に違反することになります。したがって、半明示的インスタンスはテンプレート内の静的変数には使用できません。
半明示的インスタンスは、-instances=semiexplicit オプションで指定します。
半明示的インスタンスリンケージは、定義取り込み型テンプレート編成でのみ使用できます。コンパイラは定義を検索しません。