名前空間
変種
操作

テンプレート仮引数とテンプレート実引数

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定(C++20未満)
noexcept 指定子(C++11)
例外
名前空間
指定子
decltype(C++11)
auto(C++11)
alignas(C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr(C++11)
ユーザ定義(C++11)
ユーティリティ
属性(C++11)
typedef 宣言
型エイリアス宣言(C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

すべてのテンプレートは、テンプレート宣言の構文の parameter-list で示される、1個以上のテンプレート仮引数によって、パラメータ化されます。

template<parameter-list>declaration (1)

parameter-list 内のそれぞれの仮引数は、以下のいずれかです。

  • 非型テンプレート仮引数
  • 型テンプレート仮引数
  • テンプレートテンプレート仮引数

目次

[編集]非型テンプレート仮引数

typename(オプション) (1)
typename(オプション)= default (2)
type...name(オプション) (3) (C++11以上)
placeholdername (4) (C++17以上)
1) オプショナルな名前を持つ非型テンプレート仮引数。
2) オプショナルな名前とデフォルト値を持つ非型テンプレート仮引数。
3) オプショナルな名前を持つ非型テンプレートパラメータパック
4) プレースホルダ型を持つ非型テンプレート仮引数。 placeholder は、プレースホルダ auto (単なる auto や、 auto**auto& など)推定されたクラス型のためのプレースホルダ(C++20以上)decltype(auto) を含む、任意の型であって構いません。

type は以下の型のいずれかです (cv 修飾されていても構いません。 修飾子は無視されます)。

(C++20未満)
  • 以下の両方を満たす型
  • LiteralType を満たす
  • 強い構造的等価性を持つ (後述)
これには、整数型ポインタ型メンバポインタ型std::nullptr_t、およびカスタム operator<=> オーバーロードを持たない列挙型が含まれますが、浮動小数点型は除かれます。

const T 型の glvalue x について、以下を満たす場合、その型は強い構造的等価性を持ちます。

  • T が非クラス型の場合
  • x <=> xstd::strong_ordering または std::strong_equality 型の有効な式である。
  • T がクラス型の場合
  • T の定義内で operator== がデフォルト化定義されており、さらに
  • x==x が文脈的に bool に変換されたときに well-formed であり、さらに
  • T のすべての基底クラス部分オブジェクトおよび非静的データメンバが再帰的に強い構造的等価性を持ち、さらに
  • T が mutable または volatile な部分オブジェクトを持たない。
(C++20以上)

配列および関数型をテンプレート宣言に書いても構いませんが、それらは適切なオブジェクトへのポインタまたは関数へのポインタに自動的に置き換えられます。

非型テンプレート仮引数の名前がクラステンプレート本体内の式で使用されたとき、その型が左辺値参照型またはクラス型(C++20以上)でない限り、それは変更不可能な prvalue です。

たとえ他の場所では class Foo複雑型指定子であって class Foo x;Foo 型の x を宣言するのであっても、 class Foo 形式のテンプレート仮引数は名前を持たない Foo 型の非型テンプレート仮引数ではありません。

非型テンプレート仮引数の型は、プレースホルダ型 (auto、推定されたクラス型のためのプレースホルダ(C++20以上)、または decltype(auto)) を含む場合は、推定されます。 推定は、架空の宣言 T x = template-argument; において変数 x の型を推定するかのように行われます (T は宣言されたテンプレート仮引数の型です)。 推定された型が非型テンプレート仮引数の型として許されない場合は、プログラムは ill-formed です。

template<auto n>struct B {/* ... */}; B<5> b1;// OK、非型テンプレート仮引数の型は int です。 B<'a'> b2;// OK、非型テンプレート仮引数の型は char です。 B<2.5> b3;// エラー、非型テンプレート仮引数の型は double にできません。

プレースホルダ型を使用する非型テンプレートパラメータパックの場合は、型はテンプレート実引数のそれぞれについて個別に推定され、一致する必要はありません。

template<auto...>struct C {}; C<'C', 0, 2L, nullptr> x;// OK
(C++17以上)

クラス型 T の非型テンプレート仮引数を表す識別子は、静的記憶域期間を持つ const T 型のオブジェクトを表します。 これはテンプレート仮引数オブジェクトと呼ばれ、その値は対応するテンプレート実引数がテンプレート仮引数の型に変換されたものです。 プログラム内の同じ型および同じ値を持つそのようなテンプレート仮引数はすべて同じテンプレート仮引数オブジェクトを表します。

struct A {friendbool operator==(const A&, const A&)=default;};template<A a>void f(){&a;// OK。const A& ra = a, &rb = a;// どちらも同じテンプレート仮引数オブジェクトに束縛されます。assert(&ra ==&rb);// パスします。}
(C++20以上)

[編集]型テンプレート仮引数

type-parameter-keyname(オプション) (1)
type-parameter-keyname(オプション)= default (2)
type-parameter-key...name(オプション) (3) (C++11以上)
type-constraintname(オプション) (4) (C++20以上)
type-constraintname(オプション)=default (5) (C++20以上)
type-constraint...name(オプション) (6) (C++20以上)
type-constraint - コンセプトの名前、またはコンセプトの名前の後に (山括弧で囲った) テンプレート実引数のリストが続いたものの、いずれか。 いずれの場合でも、コンセプトの名前は修飾名でも構いません。

type-parameter-keytypenameclass のいずれかです。 型テンプレート仮引数の宣言において、これらのキーワードに違いはありません。

1) デフォルト値なしの型テンプレート仮引数。
template<class T>class My_vector {/* ... */};
2) デフォルト値付きの型テンプレート仮引数。
template<class T =void>struct My_op_functor {/* ... */};
3) 型テンプレートパラメータパック
template<typename... Ts>class My_tuple {/* ... */};

仮引数の名前はオプショナルです。

// 型テンプレート仮引数を持つテンプレートの宣言。template<class>class My_vector;template<class=void>struct My_op_functor;template<typename...>class My_tuple;

テンプレート宣言の本体の中では、型引数の名前は typedef 名であり、そのテンプレートが実体化されたときに供給された型のエイリアスとなります。

type-constraint がコンセプト C を指定する Q である制約付き引数 P はそれぞれ、以下のルールに従って制約式E を導入します。

  • QC である (実引数リストを持たない) 場合、
  • P がパラメータパックでなければ、 E は単純に C<P> です。
  • そうでなければ (P がパラメータパックの場合)、 E は畳み込み式 (C<P> && ...) です。
  • QC<A1,A2...,AN> の場合、 E はそれぞれ C<P,A1,A2,...AN> または (C<P,A1,A2,...AN> && ...) です。
template<typename T> concept C1 =true;template<typename... Ts> concept C2 =true;// 可変長引数コンセプトtemplate<typename T, typename U> concept C3 =true;   template<C1 T>struct s1;// 制約式は C1<T> です。template<C1... T>struct s2;// 制約式は (C1<T> && ...) です。template<C2... T>struct s3;// 制約式は (C2<T> && ...) です。template<C3<int> T>struct s4;// 制約式は C3<T, int> です。template<C3<int>... T>struct s5;// 制約式は (C3<T, int> && ...) です。
(C++20以上)

[編集]テンプレートテンプレート仮引数

template<parameter-list>typename(C++17)|classname(オプション) (1)
template<parameter-list>typename(C++17)|classname(オプション)=default (2)
template<parameter-list>typename(C++17)|class...name(オプション) (3) (C++11以上)
1) オプショナルな名前を持つテンプレートテンプレート仮引数。
2) オプショナルな名前とデフォルト値を持つテンプレートテンプレート仮引数。
3) オプショナルな名前を持つテンプレートテンプレートパラメータパック

型テンプレート仮引数の宣言と異なり、テンプレートテンプレート仮引数の宣言はキーワード 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;};

[編集]テンプレート実引数

テンプレートを実体化するためには、すべてのテンプレート仮引数 (型、非型、またはテンプレート) を対応するテンプレート実引数で置き換えなければなりません。 クラステンプレートの場合、実引数は、明示的に提供する初期化子から推定する(C++17以上)、デフォルト値を用いる、のいずれかです。 関数テンプレートの場合、実引数は、明示的に提供する、文脈から推定する、デフォルト値を用いる、のいずれかです。

実引数が型識別子と式のいずれにも解釈できる場合は、たとえ対応するテンプレート仮引数が非型であっても、常に型識別子として解釈されます。

template<class T>void f();// #1template<int I>void f();// #2void g(){ f<int()>();// 「int()」は、型と式のどちらでもあります。// これは、型として解釈されるため、 #1 を呼びます。}

[編集]非型テンプレート実引数

非型テンプレート仮引数を持つテンプレートを実体化するときは以下の制限が適用されます。

  • 整数型および算術型の場合、実体化の際に提供されるテンプレート実引数は、そのテンプレート仮引数の型の変換された定数式でなければなりません (そのため一部の暗黙の変換が適用されます)。
  • オブジェクトへのポインタの場合、テンプレート実引数は静的記憶域期間およびリンケージ (内部でも外部でも) を持つ完全オブジェクトのアドレスを指すか、適切なヌルポインタまたは std::nullptr_t 値に評価される定数式でなければなりません。
  • 関数へのポインタの場合、有効な実引数はリンケージを持つ関数へのポインタ (またはヌルポインタ値に評価される定数式) です。
  • 左辺値参照の仮引数の場合、実体化時に提供される実引数は、一時オブジェクト、名前のない左辺値、リンケージを持たない名前付き左辺値であることはできません (別の言い方をすると、実引数はリンケージを持たなければなりません。
  • メンバポインタの場合、実引数は &Class::Member のように表されるメンバポインタであるか、ヌルポインタまたは std::nullptr_t 値に評価される定数式でなければなりません。

特に、これは、文字列リテラル、配列の要素のアドレス、非静的メンバのアドレスを、対応する非型テンプレート仮引数がオブジェクトへのポインタであるテンプレートを実体化するためのテンプレート実引数としては使用できない、ということを暗に示します。

(C++17未満)

非型テンプレート仮引数で使用できるテンプレート実引数には、そのテンプレート仮引数の型の任意の変換された定数式を使用できます。

template<constint* pci>struct X {};int ai[10]; X<ai> xi;// OK、配列からポインタへの変換および cv 修飾の変換。   struct Y {};template<const Y& b>struct Z {}; Y y; Z<y> z;// OK、変換なし。   template<int(&pa)[5]>struct W {};int b[5]; W<b> w;// OK、変換なし。   void f(char);void f(int);template<void(*pf)(int)>struct A {}; A<&f> a;// OK、オーバーロード解決により f(int) が選択されます。

唯一の例外は、参照またはポインタ型の非型テンプレート仮引数およびクラス型の非型テンプレート仮引数における参照またはポインタ型の非静的データメンバおよびその部分オブジェクト(C++20以上)は、以下のアドレスを表す/参照することはできないということです。

  • 部分オブジェクト (非静的クラスメンバ、基底部分オブジェクト、配列の要素など)
  • 一時オブジェクト (参照初期化中に作成されたものなど)
  • 文字列リテラル
  • typeid の結果
  • 定義済み変数 __func__
template<class T, constchar* p>class X {}; X<int, "Studebaker"> x1;// エラー、文字列リテラルはテンプレート実引数として使用できません。   template<int* p>class X {};int a[10];struct S {int m;staticint s;} s; X<&a[2]> x3;// エラー、配列要素のアドレス。 X<&s.m> x4;// エラー、非静的メンバのアドレス。 X<&s.s> x5;// OK、静的メンバのアドレス。 X<&S::s> x6;// OK、静的メンバのアドレス。   template<constint& CRI>struct B {}; B<1> b2;// エラー、テンプレート実引数に対して一時オブジェクトが要求されます。int c =1; B<c> b1;// OK。
(C++17以上)

[編集]型テンプレート実引数

型テンプレート仮引数に対するテンプレート実引数は、型識別子でなければなりません。 これは不完全型を表していても構いません。

template<typename T>class X {};// クラステンプレート。   struct A;// 不完全型。typedefstruct{} B;// 名前のない型への型エイリアス。   int main(){ X<A> x1;// OK、「A」は型を表します。 X<A*> x2;// OK、「A*」は型を表します。 X<B> x3;// OK、「B」は型を表します。}

[編集]テンプレートテンプレート実引数

テンプレートテンプレート仮引数に対するテンプレート実引数は、クラステンプレートまたはテンプレートエイリアスを表す識別子式でなければなりません。

実引数がクラステンプレートの場合は、仮引数をマッチングするとき、プライマリテンプレートのみが考慮されます。 部分特殊化 (もしあれば) は、そのテンプレートテンプレート仮引数に基づいた特殊化が実体化されることになったときにのみ、考慮されます。

template<typename T>class A {int x;};// プライマリテンプレート。template<class T>class A<T*>{long x;};// 部分特殊化。   // テンプレートテンプレート仮引数 V を持つクラステンプレート。template<template<typename>class V>class C { V<int> y;// プライマリテンプレートを使用します。 V<int*> z;// 部分特殊化を使用します。};   C<A> c;// c.y.x は int 型で、 c.z.x は long 型です。

テンプレートテンプレート実引数 A がテンプレートテンプレート仮引数 P にマッチするためには、 A のテンプレート仮引数のそれぞれが P の対応するテンプレート仮引数に正確にマッチしなければなりません(C++17未満)P は少なくとも A と同程度に特殊化されていなければなりません(C++17以上)P の仮引数リストがパラメータパックを含む場合は、 A のテンプレート仮引数リストから0個以上のテンプレート仮引数 (またはパラメータパック) がそれにマッチされます。

template<typename T>struct eval;// プライマリテンプレート。   template<template<typename, typename...>class TT, typename T1, typename... Rest>struct eval<TT<T1, Rest...>>{};// eval の部分特殊化。   template<typename T1>struct A;template<typename T1, typename T2>struct B;template<int N>struct C;template<typename T1, int N>struct D;template<typename T1, typename T2, int N =17>struct E;   eval<A<int>> eA;// OK、 eval の部分特殊化にマッチします。 eval<B<int, float>> eB;// OK、 eval の部分特殊化にマッチします。 eval<C<17>> eC;// エラー、 TT の第1仮引数が型テンプレート仮引数であるのに対して、// 17 は型を表さないため、// C は部分特殊化の TT にマッチしません。 eval<D<int, 17>> eD;// エラー、 TT の第2仮引数が型パラメータパックであるのに対して、// 17 は型を表さないため、// D は部分特殊化の TT にマッチしません。 eval<E<int, float>> eE;// エラー、 E の第3仮引数 (デフォルト値を使用) は非型であるため、// E は部分特殊化の TT にマッチしません。
template<class T>class A {/* ... */};template<class T, class U = T>class B {/* ... */};template<class ...Types>class C {/* ... */};   template<template<class>class P>class X {/* ... */}; X<A> xa;// OK X<B> xb;// CWG 150 適用後の C++17 では OK// それより前ではエラー (正確なマッチでない) X<C> xc;// CWG 150 適用後の C++17 では OK// それより前ではエラー (正確なマッチでない)   template<template<class ...>class Q>class Y {/* ... */}; Y<A> ya;// OK Y<B> yb;// OK Y<C> yc;// OK   template<auto n>class D {/* ... */};// 注: C++17template<template<int>class R>class Z {/* ... */}; Z<D> zd;// OK   template<int>struct SI {/* ... */};template<template<auto>class>void FA();// 注: C++17 FA<SI>();// エラー

形式的には、以下の2つの関数テンプレートへの書き換えが与えられたとき、関数テンプレートのための半順序のルールに従って、 P に対応する関数テンプレートが少なくとも A に対応する関数テンプレートと同程度に特殊化されていれば、テンプレートテンプレート仮引数 P は少なくともテンプレートテンプレート実引数 A と同程度に特殊化されています。 A のテンプレート仮引数リスト (デフォルト引数を含みます) を持つ架空のクラステンプレート X が与えられたとき、

  • 2つの関数テンプレートはそれぞれ P または A と同じテンプレート仮引数を持ちます。
  • それぞれの関数テンプレートは関数引数を1個もちます。 その型はそれぞれの関数テンプレートのテンプレート仮引数に対応するテンプレート実引数を用いた X の特殊化です。 ただし、その関数テンプレートのテンプレート仮引数リスト内のテンプレート仮引数 PP のそれぞれについて、対応するテンプレート実引数 AA が形成されます。 PP がパラメータパックを宣言する場合は、 AA はパック展開 PP... です。 そうでなければ、 AA は識別子式 PP です。

書き換えが無効な型を生成する場合は、 P は少なくとも A と同程度に特殊化されてはいません。

(C++17以上)

[編集]デフォルトテンプレート引数

デフォルトテンプレート引数は、仮引数リスト内で = 記号の後に指定されます。 デフォルトはいかなる種類のテンプレート引数 (型、非型、テンプレート) に対しても指定できますが、パラメータパックにはできません。

プライマリクラステンプレート、プライマリ変数テンプレート(C++14以上)またはエイリアステンプレートに対してデフォルトが指定されている場合は、そのテンプレート引数より後のテンプレート引数はすべてデフォルト引数を持たなければなりません。 ただし、最後の引数はパラメータパックでも構いません。 関数テンプレートでは、デフォルトの後の引数に対する制限はありません。 また、デフォルトを持つか実引数から推定できる場合に限り、パラメータパックの後に型引数があっても構いません。

デフォルト引数は以下の場所では使用できません。

(C++11未満)

フレンド関数テンプレートの宣言では、デフォルトテンプレート引数は、その宣言が定義であり、その関数の他の宣言がその翻訳単位に現れない場合にのみ許されます。

(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;

しかし、同じスコープで同じ引数にデフォルト引数を複数回与えることはできません。

template<typename T =int>class X;template<typename T =int>class X {};// エラー。

テンプレートテンプレート仮引数のテンプレート仮引数リストは、それ自身のデフォルト引数を持つことができます。 これはそのテンプレートテンプレート仮引数自身がスコープ内である場合にのみ効果があります。

// デフォルト付きの型テンプレート仮引数を持つクラステンプレート。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> です。}

デフォルトテンプレート引数で使用された名前のメンバアクセスは、使用の地点ではなく、宣言時にチェックされます。

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以上)

[編集]

[編集]非型テンプレート引数

#include <iostream>   // 単純な非型テンプレート引数。template<int N>struct S {int a[N];};   template<constchar*>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]> s2;// エラー、配列の要素はリンケージを持ちません。 S2<okay> s2;// 動作します。   int a[5];int f(int n){return n;}   int main(){ S<10> s;// s.a は int 10個の配列です。 s.a[9]=4;   Complicated<'2', a, f, &S<10>::a> c; c.foo('0');   std::cout<< s.a[9]<< a[4]<<'\n';}

出力:

42
close