[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
C++ のテンプレートは、普通 UNIX システムに見られるようなものよりも、 環境からより多くの情報を必要とするような言語機能の最初のものである。 コンパイラとリンカは、各テンプレートの実体は、それが必要なら 実行形式の中でただ一つしか存在すること、そしてそれ以外にはないことを なんとかして保証しなければならない。 この問題に対するアプローチには二つの基本的な方法がある。 以下では、それらを Boralnd モデルと Cfront モデルと呼ぶ。
Borland C++ はテンプレートの実体化問題を解決するのに、 共通ブロックに等価なコードをリンカに追加した。 コンパイラは、テンプレートの実体を、それを使っているコンパイル単位毎に 出力し、リンカがそれらを一緒にまとめる。 このモデルの良いところは、リンカはオブジェクトファイルの面倒を見るだけで 良いということである。オブジェクトファイル以外には何も考えなくて良い。 このモデルの欠点は、テンプレートコードが繰り返しコンパイルされるので、 コンパイル時間が長くなることである。 このモデル向けに書いたコードはヘッダファイル中の全てのテンプレート定義を インクルードしがちである。実体化するには見えていなくてはならないからである。
AT&T の C++ トランスレータである Cfront はテンプレートの実体化問題を 解決するのに、テンプレートのリポジトリという概念を作り出した。 テンプレートリポジトリトは、テンプレートの実体が格納され、 自動的に維持される場所である。 より最近のバージョンのリポジトリの仕組みは以下の通りである。 個々のオブジェクトファイルが構築されると、コンパイラは見つけた テンプレートの定義と実体をどんなものでもリポジトリに置く。 リンク時に、リンクラッパがリポジトリ中のオブジェクトファイルに追加され、 まだ出力されていない実体で必要なものがコンパイルされる。 このモデルの良いところは、コンパイル速度が速いということとシステムの リンカをそのまま使えるということである。 Borland モデルを実装するには、コンパイラベンダはリンカも置き換える 必要がある。Cfront モデルの欠点は、とてつもなく複雑さが増し、 そのため問題が起きる可能性も大きくなる。コードによってはこの方法は 透過的だが、実際には一つのディレクトリで複数のプログラムを構築したり、 一つのプログラムが複数のディレクトリにわかれているプログラムを 構築するのが大変難しくなる。 このモデル向けに書いたコードはインライン展開されないメンバテンプレートを 別のファイルで分離して定義し、別ファイルを別々にコンパイルする傾向がある。
GNU ld バージョン 2.8 以降を、Linux/GNU、Solaris 2、Microsoft Windows のような ELF システムで使うときは、g++ は Borland モデルを使用する。 他のシステムでは、g++ はどちらの自動的に処理の行なわれるモデルも 実装していない。
将来の g++ は、ハイブリッドモデルをサポートする予定である。 ハイブリッドモデルでは、GCC は コンパイルに含まれるテンプレート定義 に対するどんな実体化でも生成し、テンプレート定義と実体化の コンテキスト情報をオブジェクトファイルに格納する。 リンクラッパは、必要に応じて情報を抽出し、GCC を起動して残りの 実体化を生成する。その後で、リンカが重複した実体化を組み合わせる。
現時点では、テンプレートの実体化の取扱いには以下のオプションがある。
これは、Borland モデルで書かれたアプリケーションコードには最善の
選択である。Cfront モデルで書かれたコードは、修正を行って
テンプレート定義が、実体化の一つ以上の点利用可能になるようにする
必要があるだろう。普通この修正は、各テンプレートヘッダの最後に
#include <tmethods.cc>
を追加するだけである。
ライブラリコードの場合、そのライブラリで必要になるテンプレートの 実体化を全て提供したいのなら、単にそのオブジェクトファイルを全て 一緒にリンクすれば良い。リンクは失敗するが、副作用として実体化が 引き起こされる。ただし、注意しなければならないのは、 複数のライブラリが同じ実体化を提供しようとすると衝突が発生する事である。 もっとうまく扱うには、次のオプションで説明される明示的な実体化を 使うこと。
#include "Foo.h" #include "Foo.cc" template class Foo<int>; template ostream& operator << (ostream&, const Foo<int>&); |
上のような小さなファイルを必要な実体毎にを作ったり、これらkらテンプレート 実体化ライブラリを作ることができる。
Cfront モデルのコードを使っている場合、メンバテンプレート定義を ‘#include’ していないファイルをコンパイルするときに ‘-fno-implicit-templates’ オプションを使うと、おそらく 回避できるだろう。
実体化を行うのに一つの大きなファイルを使うなら、 ‘-fno-implicit-templates’ なしでコンパイルして、明示的な 実体化で必要な(しかし、他のどのファイルでも必要としない)実体を全て、 それらを指定せずに、得たいこともあるだろう。
g++ は、Working Paper で概説されているテンプレート実体化構文を 拡張して、明示的な実体化の前方宣言と、テンプレートクラスに対し GCC がサポートするデータ(すなわち vtable)を、 そのメンバどれ一つ実体化することなしに実体化することを 可能にしている。
extern template int max (int, int); inline template class Foo<int>; |
template class A<int>; template ostream& operator << (ostream&, const A<int>&); |
この戦略は、どちらのモデル向けに書かれたコードでも動作する。 Cfront モデル向けに書かれたコードを使う場合は、クラステンプレートを 含むファイルとそのメンバテンプレートを含むファイルは、同じコンパイル単位で 実装されるべきである。
ちょっとだけ違う方法として、代わりにオプション ‘-falt-external-templates’ を使う方法がある。このオプションを 指定すると、テンプレートの実体が、テンプレートが定義されているファイルを 実装する翻訳単位ではなく、最初に実体化されるヘッダを 実装している翻訳単位に生成される。このヘッダは全ての翻訳単位で 同じでなければならない。そうなってないとおそらく破綻するだろう。
これらのプラグマについてのより詳細な議論は、 See section Declarations and Definitions in One Header。
This document was generated
using texi2html 1.78.