名前空間
変種
操作

テンプレート

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (非推奨)
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
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

テンプレートは以下のいずれかを定義する C++ のエンティティです。

テンプレートはひとつ以上のテンプレート引数によってパラメータ化されます。 テンプレート引数には型テンプレート引数、非型テンプレート引数、テンプレートテンプレート引数の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およびそれ以降)

[編集] 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 { };
 
template struct S<char[2]>;         // エラー、制約が満たされません。
template<> struct S<char[2]> { };   // エラー、制約が満たされません。
(C++20およびそれ以降)

[編集] テンプレート化されたエンティティ

テンプレート化されたエンティティ(または、文献によっては「テンプロイド」) は、テンプレート定義内で定義された (または、 lambda-expression の場合は、作成された) あらゆるエンティティです。 以下のものはすべて、テンプレート化されたエンティティです。

  • クラステンプレート、関数テンプレート、変数テンプレート
  • テンプレート化されたエンティティのメンバ (クラステンプレートの非テンプレートメンバ関数など)
  • テンプレート化されたエンティティである列挙の列挙子
  • テンプレート化されたエンティティ内部で定義または作成されたあらゆるエンティティ (ローカルクラス、ローカル変数、フレンド関数など)
  • テンプレート化されたエンティティの宣言内に現れるラムダ式のクロージャ型

例えば、以下の場合、

template<typename T> struct A { void f() {} };

関数 A::f は、関数テンプレートではありませんが、それでもテンプレート化されているとみなされます。