命名空间
变体
操作

模板

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (直到 C++17* 弃用)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

模板是 C++ 实体,定义了以下内容之一

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

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

当提供模板实参时,或者对于函数 (自 C++17 起) 模板仅推导时,它们会被替换为模板形参以获得模板的特化,即特定类型或特定函数左值。

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

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

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

目录

[编辑] 语法

template <parameter-list > requires-clause (可选) declaration (1)
export template <parameter-list > declaration (2) (直到 C++11)
template <parameter-list > concept concept-name = constraint-expression ; (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)

[编辑] 模板标识符

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

template-name <template-argument-list (可选)> (1)
operatorop <template-argument-list (可选)> (2)
operator "" identifier <template-argument-list (可选)> (3) (自 C++11 起)
(已弃用)
operator user-defined-string-literal <template-argument-list (可选)> (4) (自 C++11 起)
1) 简单模板标识符
2) 运算符函数模板标识符。
3,4) 字面量运算符 函数模板标识符。
template-name - 命名模板的标识符
op - 可重载运算符
identifier - 标识符
user-defined-string-literal - "" 后跟一个标识符


命名类模板特化的简单模板标识符命名一个类。

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

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

如果满足以下所有条件,则模板标识符是有效的 

  • 实参的数量最多与形参的数量相同,或者形参是模板形参包(自 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 的 template-name 命名受约束的非函数模板或受约束的模板模板形参,但不是未知特化的成员的成员模板,并且简单模板 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 起)

如果满足以下所有条件,则两个模板标识符是相同的 

  • 它们的 template-name s 或运算符引用相同的模板。
  • 它们对应的类型模板实参是相同的类型。
  • 由它们对应的非类型模板实参确定的模板形参值是模板实参等价的
  • 它们对应的模板模板实参引用相同的模板。

两个相同的模板标识符引用相同的变量、(自 C++14 起) 类或函数。

[编辑] 模板化实体

模板化实体(或在某些来源中称为“模板体”)是在模板定义中定义的(或者,对于lambda 表达式,创建的)(自 C++11 起)任何实体。以下所有都是模板化实体

  • 类/函数/变量(自 C++14 起) 模板
(自 C++20 起)
  • 模板化实体的成员(例如,类模板的非模板成员函数)
  • 作为模板化实体的枚举的枚举器
  • 在模板化实体中定义或创建的任何实体:局部类、局部变量、友元函数等
  • 出现在模板化实体声明中的 lambda 表达式的闭包类型
(自 C++11 起)

例如,在

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

函数 A::f 不是函数模板,但仍然被认为是模板化的。


模板化函数是函数模板或模板化的函数。

模板化类是类模板或模板化的类。

模板化变量是变量模板或模板化的变量。

(自 C++14 起)

[编辑] 关键字

template, export

[编辑] 缺陷报告

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

DR 应用于 已发布行为 正确行为
CWG 2293 C++98 确定模板是否有效的规则
标识符未提供
已提供
CWG 2682 C++98
C++14
模板化函数/模板类
(C++98)/模板化变量(C++14)的定义缺失
已添加
P2308R1 C++98 如果两个模板标识符的
对应非类型模板实参
不是模板实参等价的,则它们是不同的
如果它们对应的
非类型模板形参值是不同的,则它们是不同的
不是模板实参等价的,则它们是不同的

[编辑] 参见

C 文档 关于 泛型选择