Template parameters
すべての template は、1つ以上のテンプレートパラメータによってパラメータ化されます。
各 template-parameter-list 内のパラメータ( template declaration syntax を参照)は以下のカテゴリのいずれかに属します:
- 定数テンプレートパラメータ
- 型テンプレートパラメータ
- テンプレートテンプレートパラメータ
目次 |
定数テンプレートパラメータ
別名 non-type template parameter ( 下記 を参照)。
| type name (オプション) | (1) | ||||||||
type
name
(オプション)
=
default
|
(2) | ||||||||
type
...
name
(オプション)
|
(3) | (C++11以降) | |||||||
| type | - |
以下の型のいずれか:
|
||||
| name | - | 定数テンプレートパラメータの名前 | ||||
| default | - | デフォルトテンプレート引数 default template argument |
構造体型
は以下のいずれかの型です(任意でcv修飾可能、修飾子は無視されます):
- lvalue参照型 (オブジェクトまたは関数への);
- 整数型 ;
- ポインタ型 (オブジェクトまたは関数への);
- メンバへのポインタ型 (メンバオブジェクトまたはメンバ関数への);
- 列挙型 ;
| (C++11以降) |
|
(C++20以降) |
配列型と関数型はテンプレート宣言で記述できますが、適切なオブジェクトへのポインタと関数へのポインタに自動的に置き換えられます。
定数テンプレートパラメータの名前がクラステンプレート本体の式内で使用される場合、その型が左辺値参照型でない限り、変更不可能な prvalue となります 。またはその型がクラス型でない限り (C++20以降) 。
class Foo
という形式のテンプレートパラメータは、
Foo
型の無名定数テンプレートパラメータではありません。
たとえ通常の文脈では
class Foo
が
elaborated type specifier
であり、
class Foo x;
が
x
を
Foo
型として宣言する場合でも同様です。
|
クラス型
struct A { friend bool operator==(const A&, const A&) = default; }; template<A a> void f() { &a; // OK const A& ra = a, &rb = a; // Both bound to the same template parameter object assert(&ra == &rb); // passes } |
(C++20以降) |
型テンプレートパラメータ
| type-parameter-key name (オプション) | (1) | ||||||||
type-parameter-key
name
(オプション)
=
default
|
(2) | ||||||||
type-parameter-key
...
name
(オプション)
|
(3) | (C++11以降) | |||||||
| type-constraint name (オプション) | (4) | (C++20以降) | |||||||
type-constraint
name
(オプション)
=
default
|
(5) | (C++20以降) | |||||||
type-constraint
...
name
(オプション)
|
(6) | (C++20以降) | |||||||
| type-parameter-key | - |
typename
または
class
のいずれか。型テンプレートパラメータ宣言において、これらのキーワード間に違いはない
|
| type-constraint | - | concept の名前、またはconceptの名前とそれに続くテンプレート引数のリスト(角括弧内)のいずれか。いずれの場合も、concept名は任意で修飾可能 |
| name | - | 型テンプレートパラメータの名前 |
| default | - | デフォルトテンプレート引数 |
template<class T> class My_vector { /* ... */ };
template<class T = void> struct My_op_functor { /* ... */ };
template<My_concept T> class My_constrained_vector { /* ... */ };
template<My_concept T = void> class My_constrained_op_functor { /* ... */ };
template<My_concept... Ts> class My_constrained_tuple { /* ... */ };
パラメータ名はオプションです:
// 上記で示したテンプレートの宣言: template<class> class My_vector; template<class = void> struct My_op_functor; template<typename...> class My_tuple;
テンプレート宣言の本体では、型パラメータの名前はtypedef名であり、テンプレートがインスタンス化されたときに提供される型のエイリアスとなります。
|
制約付きテンプレートパラメータ
template<typename T> concept C1 = true; template<typename... Ts> // variadic concept concept C2 = true; template<typename T, typename U> concept C3 = true; template<C1 T> struct s1; // constraint-expression is C1<T> template<C1... T> struct s2; // constraint-expression is (C1<T> && ...) template<C2... T> struct s3; // constraint-expression is (C2<T> && ...) template<C3<int> T> struct s4; // constraint-expression is C3<T, int> template<C3<int>... T> struct s5; // constraint-expression is (C3<T, int> && ...) |
(C++20以降) |
テンプレートテンプレートパラメータ
template
<
parameter-list
>
type-parameter-key
name
(オプション)
|
(1) | ||||||||
template
<
parameter-list
>
type-parameter-key
name
(オプション)
=
default
|
(2) | ||||||||
template
<
parameter-list
>
type-parameter-key
...
name
(オプション)
|
(3) | (C++11以降) | |||||||
| type-parameter-key | - |
class
または
typename
(C++17以降)
|
テンプレート宣言の本体では、このパラメータの名前はテンプレート名です(インスタンス化するには引数が必要です)。
template<typename T> class my_array {}; // 2つの型テンプレートパラメータと1つのテンプレートテンプレートパラメータ: template<typename K, typename V, template<typename> typename C = my_array> class Map { C<K> key; C<V> value; };
テンプレートパラメータの名前解決
テンプレートパラメータの名前は、そのスコープ内(ネストされたスコープを含む)で再宣言することはできません。テンプレートパラメータはテンプレート名と同じ名前を持つことは許可されていません。
template<class T, int N> class Y { int T; // エラー: テンプレートパラメータの再宣言 void f() { char T; // エラー: テンプレートパラメータの再宣言 } }; template<class X> class X; // エラー: テンプレートパラメータの再宣言
クラステンプレートの定義外で現れるクラステンプレートのメンバーの定義において、クラステンプレートのメンバーの名前は、任意の外側のクラステンプレートのテンプレートパラメータの名前を隠しますが、そのメンバーがクラスまたは関数テンプレートである場合、そのメンバーのテンプレートパラメータは隠しません。
template<class T> struct A { struct B {}; typedef void C; void f(); template<class U> void g(U); }; template<class B> void A<B>::f() { B b; // AのB、テンプレートパラメータではない } template<class B> template<class C> void A<B>::g(C) { B b; // AのB、テンプレートパラメータではない C c; // テンプレートパラメータC、AのCではない }
クラステンプレートの定義を含む名前空間の外部に現れるクラステンプレートのメンバーの定義において、テンプレートパラメータの名前はこの名前空間のメンバーの名前を隠蔽します。
namespace N { class C {}; template<class T> class B { void f(T); }; } template<class C> void N::B<C>::f(C) { C b; // C はテンプレートパラメータであり、N::C ではない }
クラステンプレートの定義内、またはそのテンプレート定義外で現れるそのようなテンプレートのメンバーの定義において、非 dependent 基底クラスごとに、基底クラスの名前または基底クラスのメンバーの名前がテンプレートパラメータの名前と同じである場合、基底クラス名またはメンバー名はテンプレートパラメータ名を隠蔽します。
struct A { struct B {}; int C; int Y; }; template<class B, class C> struct X : A { B b; // AのB C b; // エラー: AのCは型名ではない };
デフォルトテンプレート引数
デフォルトテンプレート引数は、パラメータリスト内で = 記号の後に指定されます。デフォルト値はあらゆる種類のテンプレートパラメータ(型、定数、またはテンプレート)に対して指定できます 、ただしパラメータパックには指定できません (C++11以降) 。
プライマリクラステンプレートのテンプレートパラメータに対してデフォルトが指定された場合 、プライマリ変数テンプレート、 (C++14以降) またはエイリアステンプレートでは、後続の各テンプレートパラメータはデフォルト引数を持たなければならない 。ただし、最後のパラメータのみがテンプレートパラメータパックであってもよい (C++11以降) 。関数テンプレートでは、デフォルト値を持つパラメータに続くパラメータに制限はない 。また、パラメータパックの後にさらに型パラメータが続く場合、それらはデフォルト値を持つか、関数引数から推論可能でなければならない (C++11以降) 。
デフォルトパラメータは許可されていません
- クラステンプレートのメンバーのクラス外定義において (これらはクラス本体内部の宣言で提供されなければならない)。 非テンプレートクラスの メンバーテンプレート はクラス外定義でデフォルトパラメータを使用できることに注意 ( GCC bug 53856 を参照)
- フレンドクラステンプレート 宣言において
|
(C++11以前) |
|
フレンド関数テンプレートの宣言において、デフォルトテンプレート引数は、その宣言が定義であり、かつこの翻訳単位にこの関数の他の宣言が存在しない場合にのみ許可されます。 |
(since C++11) |
宣言内に現れるデフォルトテンプレート引数は、デフォルト関数引数と同様にマージされます:
template<typename T1, typename T2 = int> class A; template<typename T1 = int, typename T2> class A; // 上記は以下と同じ: template<typename T1 = int, typename T2 = int> class A;
しかし、同じパラメータに対して同じスコープ内でデフォルト引数を2回指定することはできません:
template<typename T = int> class X; template<typename T = int> class X {}; // エラー
定数テンプレートパラメータのデフォルトテンプレート引数を解析する際、最初のネストされていない > は、大なり演算子ではなくテンプレートパラメータリストの終了として扱われます:
template<int i = 3 > 4> // 構文エラー class X { /* ... */ }; template<int i = (3 > 4)> // OK class Y { /* ... */ };
テンプレートテンプレートパラメータのテンプレートパラメータリストは、独自のデフォルト引数を持つことができます。これらのデフォルト引数は、テンプレートテンプレートパラメータ自体がスコープ内にある場合にのみ有効です:
// クラステンプレート、デフォルト値を持つ型テンプレートパラメータ付き template<typename T = float> struct B {}; // テンプレートテンプレートパラメータTはパラメータリストを持ち、 // それはデフォルト値を持つ1つの型テンプレートパラメータで構成される template<template<typename = float> typename T> struct A { void f(); void g(); }; // 外部定義のメンバ関数テンプレート template<template<typename TT> class T> void A<T>::f() { T<> t; // エラー: スコープ内でTTにデフォルト値がありません } template<template<typename TT = char> class T> void A<T>::g() { T<> t; // OK: tはT<char>です }
Member access デフォルトテンプレートパラメータで使用される名前のメンバーアクセスは、使用時点ではなく宣言時点でチェックされます:
class B {}; template<typename T> class C { protected: typedef T TT; }; template<typename U, typename V = typename U::TT> class D: public U {}; D<C<B>>* d; // エラー: C::TT は protected です
|
デフォルトテンプレート引数は、そのデフォルト引数の値が必要とされるときに暗黙的にインスタンス化されます。ただし、テンプレートが関数の名前を指定するために使用される場合は除きます: template<typename T, typename U = int> struct S {}; S<bool>* p; // Uのデフォルト引数はこの時点でインスタンス化される // pの型はS<bool, int>* |
(C++14以降) |
注記
C++26より前、定数テンプレートパラメータは標準文書では非型テンプレートパラメータと呼ばれていました。この用語は P2841R6 / PR#7587 によって変更されました。
|
テンプレートパラメータでは、型制約は型パラメータと定数パラメータの両方に使用でき、 auto の有無によって異なります。 template<typename> concept C = true; template<C, // type parameter C auto // constant parameter > struct S{}; S<int, 0> s;
|
(C++20以降) |
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_nontype_template_parameter_auto
|
201606L
|
(C++17) | 定数テンプレートパラメータ の宣言に auto を使用 |
__cpp_nontype_template_args
|
201411L
|
(C++17) | すべての 定数テンプレート引数 に対する定数評価の許可 |
201911L
|
(C++20) | 定数テンプレートパラメータ におけるクラス型と浮動小数点型 |
例
#include <array> #include <iostream> #include <numeric> // 単純な定数テンプレートパラメータ template<int N> struct S { int a[N]; }; template<const char*> struct S2 {}; // 複雑な定数例 template < char c, // 整数型 int (&ra)[5], // オブジェクトへの左辺値参照(配列型) int (*pf)(int), // 関数へのポインタ int (S<10>::*a)[10] // メンバオブジェクトへのポインタ(int[10]型) > struct Complicated { // コンパイル時に選択された関数を呼び出し // 結果をコンパイル時に選択された配列に格納 void foo(char base) { ra[4] = pf(c - base); } }; // S2<"fail"> s2; // エラー: 文字列リテラルは使用不可 char okay[] = "okay"; // リンケージを持つ静的オブジェクト // S2<&okay[0]> s3; // エラー: 配列要素にリンケージなし S2<okay> s4; // 動作する int a[5]; int f(int n) { return n; } // C++20: NTTPはリテラルクラス型で可能 template<std::array arr> constexpr auto sum() { return std::accumulate(arr.cbegin(), arr.cend(), 0); } // C++20: クラステンプレート引数は呼び出しサイトで推論される static_assert(sum<std::array<double, 8>{3, 1, 4, 1, 5, 9, 2, 6}>() == 31.0); // C++20: NTTP引数推論とCTAD static_assert(sum<std::array{2, 7, 1, 8, 2, 8}>() == 28); int main() { S<10> s; // s.aは10個のintの配列 s.a[9] = 4; Complicated<'2', a, f, &S<10>::a> c; c.foo('0'); std::cout << s.a[9] << a[4] << '\n'; }
出力:
42
|
このセクションは不完全です
理由: より多くの例が必要 |
不具合報告
以下の動作変更欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用バージョン | 公開時の動作 | 修正後の動作 |
|---|---|---|---|
| CWG 184 | C++98 |
テンプレートテンプレートパラメータのテンプレートパラメータが
デフォルト引数を持つことを許可するかどうかが未規定 |
仕様を追加 |
| CWG 1922 | C++98 |
名前が注入クラス名であるクラステンプレートが以前の宣言の
デフォルト引数を使用できるかどうかが不明確 |
許可 |
| CWG 2032 | C++14 |
変数テンプレートについて、デフォルト引数を持つテンプレート
パラメータの後のテンプレートパラメータに対する制限がなかった |
クラステンプレートおよび
エイリアステンプレートと 同じ制限を適用 |
| CWG 2542 | C++20 | クロージャ型が構造的かどうかが不明確 | 構造的ではない |
| CWG 2845 | C++20 | クロージャ型は構造的ではなかった |
キャプチャなしの場合
構造的である |