Namespaces
Variants

Templates

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

模板是定义以下内容之一的C++实体:

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

模板通过一个或多个 模板参数 进行参数化,共有三种类型:类型模板参数、常量模板参数和模板模板参数。

当提供了模板参数时,或者对于 函数 (C++17 起) 模板(仅限推导情况),这些参数会被替换到模板形参中,从而获得模板的 特化 ,即一个具体类型或特定的函数左值。

特化也可以显式提供: 全特化 允许用于类 、变量 (C++14 起) 和函数模板, 偏特化 仅允许用于类模板 和变量模板 (C++14 起)

当类模板特化在需要完整对象类型的上下文中被引用时,或当函数模板特化在需要存在函数定义的上下文中被引用时,该模板会被 实例化 (其代码实际被编译),除非该模板已被显式特化或显式实例化。类模板的实例化不会实例化其任何成员函数,除非这些成员函数也被使用。在链接阶段,不同翻译单元生成的相同实例化会被合并。

类模板的定义在隐式实例化点必须可见,这就是为什么模板库通常将所有模板定义放在头文件中(例如 大多数boost库仅包含头文件 )。

目录

语法

template < 形参列表  > requires-子句  (可选) 声明 (1)
export template < 形参列表  > 声明 (2) (C++11前)
template < 形参列表  > concept 概念名 = 约束表达式  ; (3) (C++20起)
parameter-list - 一个非空的逗号分隔的 模板形参 列表,每个形参可以是 常量形参 类型形参 模板形参 ,或是这些形参类型的 形参包 (C++11 起)
requires-clause - (C++20 起) 用于指定模板实参 约束 requires 子句
declaration - 类(含 struct 与 union) 成员类或成员枚举类型 函数 成员函数 、命名空间作用域的静态数据成员 、类作用域的变量或静态数据成员 (C++14 起) 、或 别名模板 (C++11 起) 的声明。也可用于定义 模板特化
concept-name
constraint-expression
- 参见 约束与概念

export 是一个可选修饰符,用于将模板声明为 已导出 (当用于类模板时,会同时声明其所有成员为已导出)。实例化已导出模板的文件无需包含其定义:仅声明即可。实际实现中 export 功能较为罕见,且不同实现细节存在分歧。

(C++11 前)

模板标识符

模板标识符具有以下语法之一:

模板名  < 模板实参列表  (可选) > (1)
operator 运算符  < 模板实参列表  (可选) > (2)
operator "" 标识符 < 模板实参列表  (可选) > (3) (C++11 起)
(已弃用)
operator 用户定义字符串字面量 < 模板实参列表  (可选) > (4) (C++11 起)
1) 一个 简单模板标识符
2) 一个运算符函数模板标识符。
3,4) 一个 字面量运算符 函数模板标识符。
template-name - 用于命名模板的 标识符
op - 可重载的 运算符
identifier - 标识符
user-defined-string-literal - "" 后接标识符


一个简单的模板标识符,若其命名的是类模板特化,则它命名的是一个类。

一个命名别名模板特化的模板标识符表示一个类型。

命名函数模板特化的模板标识符表示一个函数。

若满足以下所有条件,则模板标识符为 有效 :

  • 实参数量最多与形参数量相等 或存在模板 形参包 (C++11 起)
  • 每个不可推导 非包 (C++11 起) 且无默认模板实参的形参都对应一个实参。
  • 每个模板实参都与对应的模板形参匹配。
  • 每个模板实参代入后续模板形参(若存在)的替换操作均成功。
  • 如果模板标识符是 非依赖的 ,则关联约束按如下规定满足。
(since C++20)

无效的简单模板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<>;            // 错误:第一个模板参数无默认参数
using T3 = X<1>;           // 错误:值 1 与类型参数不匹配
using T4 = X<int>;         // 错误:第二个模板参数替换失败
using T5 = X<S>;           // 正确

当简单模板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;                      // 错误:约束未满足
Ptr<int> p;                      // 错误:约束未满足
template<typename T>
struct S2 { Ptr<int> x; };       // 错误,不要求诊断
template<typename T>
struct S3 { Ptr<T> x; };         // 正确,不要求满足约束
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 起) 模板
(since C++20)
  • 模板化实体的成员(例如类模板的非模板成员函数)
  • 作为模板化实体的枚举类型的枚举项
  • 在模板化实体内部定义或创建的任何实体:局部类、局部变量、友元函数等
  • 出现在模板化实体声明中的 lambda 表达式的闭包类型
(since C++11)

例如,在

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

函数 A::f 并非函数模板,但仍被视为具有模板特性。


一个 模板化函数 是指函数模板或经过模板化的函数。

一个 模板类 是指类模板或经过模板化的类。

模板化变量 是指变量模板或经过模板化的变量。

(since C++14)

关键词

template export

缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 适用标准 发布时行为 正确行为
CWG 2293 C++98 未提供判断模板标识符是否有效的规则 已提供
CWG 2682 C++98
C++14
缺少模板化函数/模板类
(C++98)/模板化变量(C++14)的定义
已添加
P2308R1 C++98 若对应常量模板实参
非模板实参等价,则两个模板标识符不同
若对应常量模板参数值
非模板实参等价,则两者不同

参见

C 文档 关于 泛型选择