テンプレート
テンプレートは、以下のいずれかを定義するC++のエンティティです。
|
(C++11以降) |
|
(C++14以降) |
|
(C++20以降) |
テンプレートは、1つ以上のテンプレートパラメータによってパラメータ化されます。テンプレートパラメータには、型テンプレートパラメータ、非型テンプレートパラメータ、テンプレートテンプレートパラメータの3種類があります。
テンプレート引数が指定されるか、関数およびクラス(C++17以降)テンプレートでのみ推論されると、それらはテンプレートパラメータに置換され、テンプレートの特殊化 (specialization)、すなわち特定の型や特定の関数の左辺値が得られます。
特殊化は明示的に提供することもできます。完全特殊化はクラス、変数(C++14以降)、および関数テンプレートで許可されており、部分特殊化はクラステンプレートおよび変数テンプレート(C++14以降)でのみ許可されています。
クラステンプレートの特殊化が完全なオブジェクト型を要求する文脈で参照された場合、または関数テンプレートの特殊化が関数定義の存在を要求する文脈で参照された場合、そのテンプレートはインスタンス化 (instantiated) されます (そのためのコードが実際にコンパイルされます)。ただし、テンプレートがすでに明示的に特殊化されているか、明示的にインスタンス化されている場合は除きます。クラステンプレートのインスタンス化は、そのメンバ関数が使用されない限り、メンバ関数をインスタンス化しません。リンク時には、異なる翻訳単位で生成された同一のインスタンスはマージされます。
クラステンプレートの定義は、暗黙的なインスタンス化の時点で可視でなければなりません。これが、テンプレートライブラリが通常、すべてのテンプレート定義をヘッダーで提供する理由です (例: ほとんどのboostライブラリはヘッダーオンリーです)。
目次 |
[編集] 構文
template <parameter-list > requires-clause (任意) declaration |
(1) | ||||||||
export template <parameter-list > declaration |
(2) | (C++11まで) | |||||||
template <parameter-list > concept concept-name = constraint-expression ; |
(3) | (C++20以降) | |||||||
| parameter-list | - | 空ではないカンマ区切りのテンプレートパラメータのリスト。各パラメータは非型パラメータ、型パラメータ、テンプレートパラメータ、またはそれらのいずれかのパラメータパック(C++11以降)のいずれかです。 |
| requires-clause | - | (C++20以降) テンプレート引数に対する制約を指定するrequires節。 |
| 宣言 | - | クラス (structとunionを含む)、メンバクラスまたはメンバ列挙型、関数またはメンバ関数、名前空間スコープの静的データメンバ、変数またはクラススコープの静的データメンバ(C++14以降)、またはエイリアステンプレート(C++11以降)の宣言。これはテンプレートの特殊化を定義することもあります。 |
| concept-name constraint-expression |
- | 制約とコンセプトを参照 |
|
export は、テンプレートをエクスポート (exported) されたものとして宣言する任意の修飾子でした (クラステンプレートと共に使用される場合、そのすべてのメンバもエクスポートされたものとして宣言しました)。エクスポートされたテンプレートをインスタンス化するファイルは、その定義をインクルードする必要はありませんでした。宣言だけで十分でした。export の実装は稀で、詳細において互いに食い違いがありました。 |
(C++11まで) |
| このセクションは未完成です 理由: コア構文、テンプレートパラメータ、インスタンス化について、class_templateとfunction_templateの共通コンテンツをまとめるため。 |
[編集] テンプレート識別子
テンプレート識別子は、以下のいずれかの構文を持ちます。
template-name <template-argument-list (任意)> |
(1) | ||||||||
operatorop <template-argument-list (任意)> |
(2) | ||||||||
operator "" identifier <template-argument-list (任意)> |
(3) | (C++11以降) (非推奨) | |||||||
operator user-defined-string-literal <template-argument-list (任意)> |
(4) | (C++11以降) | |||||||
| template-name | - | テンプレートを指名する識別子 |
| op | - | オーバーロード可能な演算子 |
| identifier | - | 識別子 |
| user-defined-string-literal | - | "" に続く識別子 |
クラステンプレートの特殊化を指名する単純テンプレート識別子は、クラスを指名します。
エイリアステンプレートの特殊化を指名するテンプレート識別子は、型を指名します。
関数テンプレートの特殊化を指名するテンプレート識別子は、関数を指名します。
以下のすべての条件が満たされる場合、テンプレート識別子は有効 (valid) です。
- 引数の数がパラメータの数以下であるか、またはパラメータがテンプレートのパラメータパックである(C++11以降)。
- デフォルトのテンプレート引数を持たない、推論不可能な非パック(C++11以降)の各パラメータに対して引数が存在する。
- 各テンプレート引数が、対応するテンプレートパラメータに一致する。
- 各テンプレート引数を後続のテンプレートパラメータ (もしあれば) に代入することが成功する。
|
(C++20以降) |
無効な単純テンプレートIDはコンパイル時エラーですが、それが関数テンプレートの特殊化を指名する場合は除きます (この場合、SFINAEが適用される可能性があります)。
template<class T, T::type n = 0> class X; struct S { using type = int; }; using T1 = X<S, int, int>; // error: too many arguments using T2 = X<>; // error: no default argument for first template parameter using T3 = X<1>; // error: value 1 does not match type-parameter using T4 = X<int>; // error: substitution failure for second template parameter using T5 = X<S>; // OK
|
単純テンプレートIDの template-name が、制約付き非関数テンプレートまたは制約付きテンプレートテンプレートパラメータを指名し、かつ未知の特殊化のメンバであるメンバテンプレートではなく、単純テンプレートID内のすべてのテンプレート引数が非依存である場合、その制約付きテンプレートの関連する制約が満たされなければなりません。 template<typename T> concept C1 = sizeof(T) != sizeof(int); template<C1 T> struct S1 {}; template<C1 T> using Ptr = T*; S1<int>* p; // error: constraints not satisfied Ptr<int> p; // error: constraints not satisfied template<typename T> struct S2 { Ptr<int> x; }; // error, no diagnostic required template<typename T> struct S3 { Ptr<T> x; }; // OK, satisfaction is not required S3<int> x; // error: constraints not satisfied template<template<C1 T> class X> struct S4 { X<int> x; // error, no diagnostic required }; template<typename T> concept C2 = sizeof(T) == 1; template<C2 T> struct S {}; template struct S<char[2]>; // error: constraints not satisfied template<> struct S<char[2]> {}; // error: constraints not satisfied |
(C++20以降) |
以下のすべての条件が満たされる場合、2つのテンプレート識別子は同じ (same) です。
- それらの template-name または演算子が同じテンプレートを参照する。
- それらの対応する型テンプレート引数が同じ型である。
- それらの対応する非型テンプレート引数によって決定されるテンプレートパラメータ値がテンプレート引数として等価 (template-argument-equivalent) である。
- それらの対応するテンプレートテンプレート引数が同じテンプレートを参照する。
同じである2つのテンプレート識別子は、同じ変数、(C++14以降)クラス、または関数を参照します。
[編集] テンプレート化されたエンティティ
テンプレート化されたエンティティ (templated entity) (または一部の文献では "temploid" とも呼ばれる) は、テンプレート定義内で定義 (または、ラムダ式の場合は作成)(C++11以降) される任意のエンティティです。以下のすべてがテンプレート化されたエンティティです。
- クラス/関数/変数(C++14以降)テンプレート
| (C++20以降) |
- テンプレート化されたエンティティのメンバ (クラステンプレートの非テンプレートメンバ関数など)
- テンプレート化されたエンティティである列挙型の列挙子
- テンプレート化されたエンティティ内で定義または作成された任意のエンティティ: ローカルクラス、ローカル変数、フレンド関数など
|
(C++11以降) |
例えば、以下において
template<typename T> struct A { void f() {} };
関数 A::f は関数テンプレートではありませんが、それでもテンプレート化されていると見なされます。
テンプレート化された関数 (templated function) は、関数テンプレートまたはテンプレート化された関数です。
テンプレート化されたクラス (templated class) は、クラステンプレートまたはテンプレート化されたクラスです。
|
テンプレート化された変数 (templated variable) は、変数テンプレートまたはテンプレート化された変数です。 |
(C++14以降) |
[編集] キーワード
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 2293 | C++98 | テンプレートが有効かどうかを決定するルール 識別子が有効かどうかの判断ルールが提供されていなかった |
提供された |
| CWG 2682 | C++98 C++14 |
テンプレート化された関数/テンプレートクラスの定義 (C++98)/テンプレート化された変数 (C++14) の定義が欠けていた |
追加された |
| P2308R1 | C++98 | 2つのテンプレート識別子が異なるとされたのは、それらの 対応する非型テンプレート引数が テンプレート引数として等価でない場合 |
それらが異なるとされるのは、それらの対応する 非型テンプレートパラメータ値が異なる場合 テンプレート引数として等価でない場合 |
[編集] 関連項目
| C ドキュメント の ジェネリック選択
|