模板
模板是一個 C++ 實體,它定義以下其一:
|
(C++11 起) |
|
(C++14 起) |
|
(C++20 起) |
模板以一個或多個模板形參參數化,形參有三種:類型模板形參、非類型模板形參和模板模板形參。
當提供了模板實參,或當函數模板或類(C++17 起)模板的模板實參被推導出時,它們替換各模板形參,以獲得模板的一個特化,���一個特定類型或一個特定函數左值。
特化也可以顯式提供:對類、變量(C++14 起)和函數模板都允許全特化,只允許對類模板和變量模板(C++14 起)部分特化。
在要求完整對象類型的語境中引用某個類模板特化時,或在要求函數定義存在的語境中引用某個函數模板特化時,除非模板已經被顯式特化或顯式實例化,否則模板即被實例化(它的代碼被實際編譯)。類模板的實例化不會實例化其任何成員函數,除非它們也被使用。在鏈接時,不同翻譯單元生成的相同實例被合併。
模板的定義必須在隱式實例化點可見,這就是模板庫通常都在頭文件中提供所有模板定義的原因(例如大多數 boost 庫只有標頭)
語法
template <形參列表 > requires子句 (可選) 聲明
|
(1) | ||||||||
export template <形參列表 > 聲明
|
(2) | (C++11 前) | |||||||
template <形參列表 > concept 概念名 = 約束表達式 ;
|
(3) | (C++20 起) | |||||||
| 形參列表 | - | 非空的模板形參的逗號分隔列表,其中每項是非類型形參、類型形參、模板形參或任何這些的形參包之一。 |
| requires子句 | - | (C++20 起) 指定了各模板實參上的約束的 requires子句。 |
| 聲明 | - | 類,成員類或成員枚舉類型,函數或成員函數,命名空間作用域的靜態數據成員,變量或類作用域的靜態數據成員,(C++14 起)或別名模板(C++11 起)的聲明。它也可以定義模板特化。 |
| 概念名 約束表達式 |
- | 見約束與概念 |
|
|
(C++11 前) |
| 本節未完成 原因:核心語法,模板形參,以及實例化,帶出 class_template 和 function_template 間的公共內容 |
模板標識
模板標識具有以下語法:
模板名 <模板實參列表 (可選)>
|
(1) | ||||||||
operator運算符 <模板實參列表 (可選)>
|
(2) | ||||||||
operator "" 標識符 <模板實參列表 (可選)>
|
(3) | (C++11 起) (棄用) | |||||||
operator 用戶定義字符串字面量 <模板實參列表 (可選)>
|
(4) | (C++11 起) | |||||||
| 模板名 | - | 命名模板的標識符 |
| 運算符 | - | 可重載標識符 |
| 標識符 | - | 標識符 |
| 用戶定義字符串字面量 | - | "" 後隨一個標識符
|
指名類模板特化的簡單模板標識指名一個類。
指名別名模版特化的模板標識指名一個類型。
指名函數模板特化的模板標識指名一個函數。
模板標識在滿足以下所有條件時合法:
- 實參數量不大於形參數量,或有一個形參是模板形參包(C++11 起)。
- 每個沒有默認模板實參的不可推導的非包(C++11 起)形參都有一個實參。
- 每個模板實參都與對應的模板形參相匹配。
- 替換每個模板實參到它的後續模板形參(如果存在)中均成功。
|
(C++20 起) |
無效的簡單模板標識是編譯時錯誤,除非它指名的是函數模板特化(此時適用 SFINAE)。
template<class T, T::type n = 0>
class X;
struct S
{
using type = int;
};
using T1 = X<S, int, int>; // 错误:实参过多
using T2 = X<>; // 错误:第一个模板形参没有默认实参
using T3 = X<1>; // 错误:值 1 不匹配类型形参
using T4 = X<int>; // 错误:第二个模板形参替换失败
using T5 = X<S>; // OK
|
如果在簡單模板標識的模板名 指名受約束的非函數模板或受約束的模板模板形參,但不是作為未知特化的成員的成員模板,而且簡單模板標識中的所有模板實參均非待決,那麼必須滿足受約束模板的各項關聯約束: 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 起) |
兩個模板標識在滿足以下所有條件時相同:
- 它們的模板名 或運算符指代同一模板。
- 它們對應的類型模板實參是同一類型。
- 它們對應的非類型模板實參所確定的模板形參值模板實參等價。
- 它們對應的模板模板實參指代同一模板。
相同的兩個模板標識指代同一個變量、(C++14 起)類或函數。
模板化實體
模板化實體 是在模板定義內定義(或對於 lambda 表達式為創建)(C++11 起)的實體。下列所有實體都是模板化實體:
- 類/函數/變量(C++14 起)模板
| (C++20 起) |
- 模板化實體的成員(例如類模板的非模板成員函數)
- 作為模板化實體的枚舉的枚舉項
- 任何模板化實體中定義或創建的實體:局部類,局部變量,友元函數,等等
|
(C++11 起) |
例如,在以下模板中:
template<typename T>
struct A
{
void f() {}
};
函數 A::f 不是函數模板,但它仍然會被當做是模板化的。
模板化函數 是函數模板或模板化的函數。
模板化類 是類模板或模板化的類。
|
模板化變量 是變量模板或模板化的變量。 |
(C++14 起) |
關鍵詞
缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
| 缺陷報告 | 應用於 | 出版時的行為 | 正確行為 |
|---|---|---|---|
| CWG 2293 | C++98 | 未提供判斷模板標識是否合法的規則 | 已提供 |
| CWG 2682 | C++98 C++14 |
缺失了模板化函數/模板類(C++98)/模板化變量(C++14)的定義 | 已補充 |
| P2308R1 | C++98 | 當兩個模板標識的對應非類型模板實參並非模板實參等價時,它們不同 | 當對應非類型模板形參值並非模板實參等價時,它們不同 |
參閱
泛型選擇的 C 文檔
|