名稱空間
變體
操作

模板

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

模板是一個 C++ 實體,它定義了以下之一

(C++11 起)
(C++14 起)
(C++20 起)

模板由一個或多個模板引數引數化,模板引數有三種:型別模板引數、非型別模板引數和模板模板引數。

當提供了模板實參,或者對於函式(C++17 起)模板,僅推導實參時,這些實參將替換模板引數以獲得模板的*特化*,即特定型別或特定函式左值。

特化也可以顯式提供:類、變數(C++14 起)和函式模板允許完全特化部分特化只允許類模板和變數模板(C++14 起)

當在需要完整物件型別的上下文中引用類模板特化,或者在需要函式定義存在的上下文中引用函式模板特化時,模板將被*例項化*(其實際程式碼被編譯),除非該模板已被顯式特化或顯式例項化。類模板的例項化不會例項化其任何成員函式,除非它們也被使用。在連結時,由不同翻譯單元生成的相同例項化會被合併。

類模板的定義必須在隱式例項化點可見,這就是為什麼模板庫通常在標頭檔案中提供所有模板定義(例如,大多數 Boost 庫都是僅標頭檔案)。

目錄

[編輯] 語法

template <引數列表 > requires-clause (可選) 宣告 (1)
export template <引數列表 > 宣告 (2) (C++11 前)
template <引數列表 > concept 概念名 = 約束表示式 ; (3) (C++20 起)
引數列表 - 非空的逗號分隔的模板引數列表,每個引數要麼是非型別引數型別引數模板引數,或其中任何一種的引數包(C++11 起)
requires-clause - (C++20 起) 一個requires-clause,指定模板實參的約束
宣告 - 類(包括 struct 和 union)成員類或成員列舉型別函式成員函式、名稱空間範圍的靜態資料成員、類範圍的變數或靜態資料成員(C++14 起),或別名模板(C++11 起)的宣告。它也可以定義模板特化
概念名
約束表示式
- 參見約束與概念

export 是一個可選的修飾符,它將模板宣告為*匯出*(當與類模板一起使用時,它也宣告其所有成員為匯出)。例項化匯出模板的檔案不需要包含其定義:宣告就足夠了。export 的實現很少見,並且在細節上存在分歧。

(C++11 前)

[編輯] 模板識別符號

模板識別符號具有以下語法之一

模板名 <模板實參列表 (可選)> (1)
operator運算子 <模板實參列表 (可選)> (2)
operator "" 識別符號 <模板實參列表 (可選)> (3) (C++11 起)
(已棄用)
operator 使用者定義字串字面量 <模板實參列表 (可選)> (4) (C++11 起)
1) 簡單模板識別符號
2) 運算子函式模板識別符號。
3,4) 字面量運算子函式模板識別符號。
模板名 - 命名模板的識別符號
運算子 - 可過載運算子
識別符號 - 一個識別符號
使用者定義字串字面量 - "" 後跟一個識別符號


命名類模板特化的簡單模板識別符號命名一個類。

命名別名模板特化的模板識別符號命名一個型別。

命名函式模板特化的模板識別符號命名一個函式。

如果滿足以下所有條件,則模板識別符號是*有效*的:

  • 實引數量至多與引數數量相同,或引數是模板引數包(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 的模板名命名一個受約束的非函式模板或受約束的模板模板引數,但不是未知特化成員模板,並且簡單模板 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 起)

如果滿足以下所有條件,則兩個模板識別符號是*相同*的:

  • 它們的模板名或運算子指向同一個模板。
  • 它們對應的型別模板實參是相同的型別。
  • 由它們對應的非型別模板實參確定的模板引數值是模板實參等價的
  • 它們對應的模板模板實參指向同一個模板。

兩個相同的模板識別符號指向相同的變數、(C++14 起)類或函式。

[編輯] 模板化實體

一個*模板化實體*(或在某些資料中稱為“temploid”)是在模板定義中定義(或,對於lambda 表示式,建立)(C++11 起)的任何實體。以下所有都是模板化實體:

  • 類/函式/變數(C++14 起)模板
(C++20 起)
  • 模板化實體的成員(例如類模板的非模板成員函式)
  • 作為模板化實體的列舉的列舉器
  • 在模板化實體內定義或建立的任何實體:區域性類、區域性變數、友元函式等。
  • 出現在模板化實體宣告中的 lambda 表示式的閉包型別
(C++11 起)

例如,在

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

函式A::f不是函式模板,但仍被認為是模板化的。


模板化函式是一個函式模板或一個模板化的函式。

模板化類是一個類模板或一個模板化的類。

模板化變數是一個變數模板或一個模板化的變數。

(C++14 起)

[編輯] 關鍵詞

template, export

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 2293 C++98 沒有提供確定模板
識別符號是否有效的規則
已提供
CWG 2682 C++98
C++14
缺少模板化函式/模板類
(C++98)/模板化變數(C++14)的定義
已新增
P2308R1 C++98 如果兩個模板識別符號的
對應的非型別模板實參
不模板實參等價,則它們是不同的
如果它們的對應的
非型別模板引數值
不模板實參等價,則它們是不同的

[編輯] 另見

C 文件 關於 通用選擇