テンプレート
テンプレートは以下のいずれかを定義する C++ のエンティティです。
- クラスのファミリー (クラステンプレート) (ネストしたクラスでも構いません)
- 関数のファミリー (関数テンプレート) (メンバ関数でも構いません)
- 型のファミリーへのエイリアス (エイリアステンプレート) (C++11以上)
- 変数のファミリー (変数テンプレート) (C++14以上)
- コンセプト (制約とコンセプト) (C++20以上)
テンプレートはひとつ以上のテンプレート引数によってパラメータ化されます。 テンプレート引数には型テンプレート引数、非型テンプレート引数、テンプレートテンプレート引数の3種類があります。
テンプレート実引数が提供されたとき、または、推定されたとき (関数テンプレートおよびクラステンプレート(C++17以上)の場合のみ)、それらはテンプレートの特殊化、つまり、特定の型または特定の関数の左辺値を得るために、テンプレート仮引数を置き換えます。 特殊化は明示的に提供することもできます。 完全特殊化は関数テンプレートとクラステンプレートのどちらについても行うことができます。 部分特殊化はクラステンプレートに対してのみ行うことができます。
クラステンプレートの特殊化が完全オブジェクト型を要求する文脈で参照されたとき、または関数テンプレートの特殊化が関数の定義の存在を要求する文脈で参照されたとき、そのテンプレートがすでに明示的に特殊化または実体化されていなければ、そのテンプレートは実体化されます (そのためのコードが実際にコンパイルされます)。 クラステンプレートを実体化しても、そのメンバ関数は、使用されていない限り、実体化されません。 異なる翻訳単位によって生成された同一の実体化は、リンク時にマージされます。
テンプレートの定義は暗黙の実体化の時点で可視でなければなりません。 これがテンプレートライブラリが一般的にすべてのテンプレートの定義をヘッダで提供する理由です (例えば ほとんどの boost ライブラリはヘッダオンリーです)。
[編集]構文
template < parameter-list> requires-clause(C++20)(オプション)declaration | (1) | ||||||||
export template < parameter-list> declaration | (2) | (C++11未満) | |||||||
template < parameter-list> concept concept-name= constraint-expression; | (3) | (C++20以上) | |||||||
declaration | - | クラス (構造体および共用体を含む)、メンバクラスまたはメンバ列挙型、関数またはメンバ関数、名前空間スコープの静的データメンバ、クラススコープの変数または静的データメンバ(C++14以上)またはエイリアステンプレート(C++11以上)の宣言。 テンプレートのの特殊化を定義しても構いません。 |
parameter-list | - | テンプレート仮引数のコンマ区切りの空でないリスト。 各引数は非型引数、型引数、テンプレート引数またはそれらのいずれかのパラメータパックのいずれかです。 |
concept-name constraint-expression | - | 制約とコンセプトを参照してください。 (C++20以上) |
export はテンプレートをエクスポートされるものとして宣言するオプショナルな修飾子です (クラステンプレートで使用した場合は、そのすべてのメンバも同様にエクスポートされるものとして宣言されます)。 エクスポートされたテンプレートを実体化するファイルは、その定義を含む必要はなく、宣言するだけで十分です。 export の実装は稀であり、詳細は処理系によって異なります。 | (C++11未満) |
テンプレートの仮引数リストには、そのテンプレートの実引数に対する制約を指定するオプショナルな requires-clause を付けることができます。 | (C++20以上) |
This section is incomplete Reason: core syntax, template parameters, and instantiations, take content common between class_template and function_template |
[編集]template-id
template-name< parameter-list> | |||||||||
template-name | - | テンプレートを表す識別子 (この場合は「simple-template-id」と呼ばれます) またはオーバーロードされた演算子テンプレートまたはユーザ定義リテラルテンプレートの名前のいずれか。 |
クラステンプレートの特殊化を表す simple-template-id はクラスを表します。
エイリアステンプレートの特殊化を表す template-id は型を表します。
関数テンプレートの特殊化を表す template-id は関数を表します。
template-id は以下の場合にのみ有効です。
- 実引数の数が仮引数と同じかそれより少ない、または仮引数がテンプレートパラメータパックである。
- デフォルトテンプレート引数を持たず推定可能でなくパックでない仮引数のそれぞれについて実引数がある。
- それぞれのテンプレート実引数が対応するテンプレート仮引数とマッチする。
- それぞれのテンプレート実引数の後続のテンプレート仮引数 (もしあれば) への置き換えが成功する。
- (C++20)template-id が非依存の場合は、関連する制約が下で規定されている通りに満たされる。
無効な simple-template-id はコンパイル時エラーです。 ただしそれが関数テンプレートの特殊化を表す場合は除きます (この場合は SFINAE が適用されることがあります)。
template<class T, T::type n =0>class X;struct S {using type =int;};using T1 = X<S, int, int>;// エラー、引数が多すぎます。using T2 = X<>;// エラー、第1テンプレート引数にはデフォルト引数がありません。using T3 = X<1>;// エラー、値「1」は型引数にマッチしません。using T4 = X<int>;// エラー、第2テンプレート引数に対する置き換えに失敗。using T5 = X<S>;// OK。
simple-template-id 内の template-name が制約付きの非関数テンプレートまたは制約付きのテンプレートテンプレート引数を表すけれども、未知の特殊化のメンバであるメンバテンプレートでなく、 simple-template-id 内のすべてのテンプレート引数が非依存の場合、その制約付きテンプレートの関連する制約は満たされなければなりません。 template<typename T> concept C1 = sizeof(T)!= sizeof(int); template<C1 T>struct S1 {};template<C1 T>using Ptr = T*; S1<int>* p;// エラー、制約が満たされません。 Ptr<int> p;// エラー、制約が満たされません。 template<typename T>struct S2 { Ptr<int> x;};// エラーですが、診断は要求されません。 template<typename T>struct S3 { Ptr<T> x;};// OK、制約を満たす必要はありません。 S3<int> x;// エラー、制約が満たされません。 template<template<C1 T>class X>struct S4 { X<int> x;// エラーですが、診断は要求されません。}; template<typename T> concept C2 = sizeof(T)==1; template<C2 T>struct S {}; templatestruct S<char[2]>;// エラー、制約が満たされません。template<>struct S<char[2]>{};// エラー、制約が満たされません。 | (C++20以上) |
[編集]テンプレート化されたエンティティ
テンプレート化されたエンティティ(または、文献によっては「テンプロイド」) は、テンプレート定義内で定義された (または、 lambda-expression の場合は、作成された) あらゆるエンティティです。 以下のものはすべて、テンプレート化されたエンティティです。
- クラステンプレート、関数テンプレート、変数テンプレート(C++14以上)
- コンセプト(C++20以上)
- テンプレート化されたエンティティのメンバ (クラステンプレートの非テンプレートメンバ関数など)
- テンプレート化されたエンティティである列挙の列挙子
- テンプレート化されたエンティティ内部で定義または作成されたあらゆるエンティティ (ローカルクラス、ローカル変数、フレンド関数など)
- テンプレート化されたエンティティの宣言内に現れるラムダ式のクロージャ型
例えば、以下の場合、
template<typename T>struct A {void f(){}};
関数 A::f
は、関数テンプレートではありませんが、それでもテンプレート化されているとみなされます。