クラステンプレート
クラステンプレートはクラスのファミリーを定義します。
目次 |
[編集]構文
template < parameter-list> class-declaration | (1) | ||||||||
export template < parameter-list> class-declaration | (2) | (C++11未満) | |||||||
[編集]説明
class-declaration | - | クラス宣言。 宣言されたクラスの名前はテンプレートの名前になります。 |
parameter-list | - | 空でないコンマ区切りのテンプレート引数のリスト。 それぞれの引数は非型引数、型引数、テンプレート引数、それらのいずれかのパラメータパック、のいずれかでなければなりません。 |
export はテンプレートをエクスポートされるものとして宣言するオプショナルな修飾子です (クラステンプレートで使用したときは、そのすべてのメンバも同様にエクスポートされるものとして宣言します)。 エクスポートされたテンプレートを実体化するファイルはその定義をインクルードする必要はありません。 宣言だけで十分です。 export の実装はレアであり、詳細についてお互いに合意されていません。 | (C++11未満) |
[編集]クラステンプレートの実体化
クラステンプレートそれ自身は型でもオブジェクトでも他のいかなるエンティティでもありません。 テンプレート定義のみを含むソースファイルからは何のコードも生成されません。 何らかのコードを出現させるためにはテンプレートを実体化しなければなりません。 コンパイラが実際のクラス (または関数テンプレートからは関数) を生成できるように、テンプレート引数を提供しなければなりません。
[編集]明示的実体化
template class|struct template-name< argument-list> ; | (1) | ||||||||
extern template class|struct template-name< argument-list> ; | (2) | (C++11以上) | |||||||
明示的実体化の定義は、それが参照するクラス、構造体、または共用体を強制的に実体化します。 明示的実体化は、テンプレートの定義の後、プログラム内のどこに現れてもよく、同じ引数リストに対してはプログラム全体で一度のみ現れることが許されます。
明示的実体化の宣言 (extern テンプレート) は暗黙の実体化のステップをスキップします。 暗黙の実体化を発生させていたであろうコードは、代わりに、どこか他の場所で提供される明示的実体化の定義を使用します (そのような実体化が存在しなければリンクエラーになります)。 これはテンプレートを使用するソースファイルのうちひとつを除いたすべてで明示的に実体化を宣言し残りのファイルで明示的に実体化を定義することによってコンパイル時間を削減するために使用できます。 | (C++11以上) |
クラス、関数、変数、およびメンバテンプレートの特殊化は、そのテンプレートから明示的に実体化できます。 クラステンプレートのメンバ関数、メンバクラス、および静的データメンバは、そのメンバ定義から明示的に実体化できます。
明示的実体化は、修飾された識別子を用いる場合を除いて、そのテンプレートの囲っている名前空間内にのみ現れることができます。
namespace N {template<class T>class Y // テンプレートの定義。{void mf(){}};}// template class Y<int>; // エラー、クラステンプレート Y はグローバル名前空間では可視でありません。using N::Y;// template class Y<int>; // エラー、テンプレートの名前空間の外側での明示的実体化。templateclass N::Y<char*>;// OK、明示的実体化。templatevoid N::Y<double>::mf();// OK、明示的実体化。
同じテンプレート引数のセットに対して明示的特殊化が以前に現れている場合、明示的実体化は効果がありません。
関数テンプレート、変数テンプレート、クラステンプレートのメンバ関数または静的データメンバを明示的実体化するとき、可視であるために宣言のみが要求されます。 同じテンプレート引数を用いた明示的特殊化が以前に現れている場合を除いて、クラステンプレート、クラステンプレートのメンバクラス、またはメンバクラステンプレートの明示的実体化より前に、完全な定義が現れていなければなりません。
関数テンプレート、変数テンプレート、メンバ関数テンプレート、またはクラステンプレートのメンバ関数または静的データメンバが明示的実体化の定義を用いて明示的に実体化される場合は、同じ翻訳単位内にテンプレートの定義が存在しなければなりません。
明示的実体化がクラステンプレートの特殊化を表すとき、それはその翻訳単位内でまだ明示的に特殊化されていないそのクラスの非継承非テンプレートメンバそれぞれの同じ種類 (宣言または定義) の明示的実体化として動作します。 この明示的実体化が定義の場合、それはその時点ですでに定義されているメンバのみに対する明示的実体化の定義でもあります。
明示的実体化の定義はメンバアクセス指定子を無視します。 引数の型および戻り値の型がプライベートでも構いません。
[編集]暗黙の実体化
完全に定義された型を要求する文脈でコードがテンプレートを参照するとき、または型の完全性がコードに影響し、その特定の型がまだ明示的に実体化されていないとき、暗黙の実体化が発生します。 例えば、その型のオブジェクトが構築されるときはそうですが、その型へのポインタが構築されるときはそうではありません。
これはクラステンプレートのメンバにも適用されます。 そのメンバがプログラム内で使用されなければ、それは実体化されず、定義を要求しません。
template<class T>struct Z // テンプレートの定義。{void f(){}void g();// 定義はありません。};templatestruct Z<double>;// Z<double> の明示的実体化。 Z<int> a;// Z<int> の暗黙の実体化。 Z<char>* p;// ここでは何も実体化されません。 p->f();// ここでは Z<char> および Z<char>::f() の暗黙の実体化が発生します。// Z<char>::g() は必要となることはなく、実体化されることはありません。 定義する必要はありません。
クラステンプレートが宣言されたけれども定義されていないときは、実体化の時点で不完全クラス型を生成します。
template<class T>class X;// 宣言。 定義ではありません。 X<char> ch;// エラー、 X<char> は不完全型です。
ローカルクラスおよびそのメンバ内で使用されるあらゆるテンプレートは、そのローカルクラスまたは列挙が宣言されているエンティティの実体化の一部として実体化されます。 | (C++17以上) |
[編集]関連項目
- テンプレート引数はテンプレートのパラメータ化を可能にします。
- 関数テンプレート宣言は関数テンプレートを宣言します。
- テンプレートの特殊化は既存のテンプレートを特定の型に対して定義します。
- パラメータパックはテンプレート内での型のリストの使用を可能にします(C++11以上)。