C++ 参考手册
- C++11
- C++14
- C++17
- C++20
- C++ 编译器支持情况表
- 独立与宿主实现
- C++ 语言
- 变量模板(C++14 起)
- 整数字面量
- 聚合初始化
- 比较运算符
- 默认比较(C++20 起)
- 转义序列
- for 循环
- while 循环
- 用户定义转换
- SFINAE
- 主函数
- ASCII 码表
- 标识符
- 类型
- 内存模型
- 对象
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 类
- 运算符重载
- 模板
- 异常
- 事务性内存
- 占位符类型说明符 (C++11 起)
- decltype 说明符
- 函数声明
- final 说明符 (C++11 起)
- override 说明符(C++11 起)
- 引用声明
- 移动构造函数
- 移动赋值运算符
- 枚举声明
- constexpr 说明符(C++11 起)
- 列表初始化 (C++11 起)
- 构造函数与成员初始化器列表
- using 声明
- nullptr,指针字面量
- 基础类型
- 类型别名,别名模版 (C++11 起)
- 形参包
- 联合体声明
- 字符串字面量
- 用户定义字面量 (C++11 起)
- 属性说明符序列(C++11 起)
- Lambda 表达式 (C++11 起)
- noexcept 说明符 (C++11 起)
- noexcept 运算符 (C++11 起)
- alignof 运算符(C++11 起)
- alignas 说明符 (C++11 起)
- 存储类说明符
- 基于范围的 for 循环 (C++11 起)
- static_assert 声明
- 隐式转换
- 代用运算符表示
- 自增/自减运算符
- 折叠表达式(C++17 起)
- 类模板实参推导(C++17 起)
- 模板形参与模板实参
- if 语句
- inline 说明符
- 结构化绑定声明 (C++17 起)
- switch 语句
- 字符字面量
- 命名空间
- 求值顺序
- 复制消除
- consteval 说明符 (C++20 起)
- constinit 说明符 (C++20 起)
- 协程 (C++20)
- 模块 (C++20 起)
- 约束与概念 (C++20 起)
- new 表达式
- do-while 循环
- continue 语句
- break 语句
- goto 语句
- return 语句
- 动态异常说明
- throw 表达式
- try 块
- 命名空间别名
- 类声明
- cv(const 与 volatile)类型限定符
- 默认初始化
- 值初始化(C++03 起)
- 零初始化
- 复制初始化
- 直接初始化
- 常量初始化
- 引用初始化
- 值类别
- C++ 运算符优先级
- 布尔字面量
- 浮点字面量
- typedef 说明符
- 显式类型转换
- static_cast 转换
- dynamic_cast 转换
- const_cast 转换
- reinterpret_cast 转换
- delete 表达式
- 构造函数与成员初始化器列表
- this 指针
- 访问说明符
- 友元声明
- virtual 函数说明符
- explicit 说明符
- 静态成员
- 默认构造函数
- 复制构造函数
- 复制赋值运算符
- 析构函数
- 类模板
- 函数模板
- 显式(全)模板特化
- 汇编声明
- C++ 的历史
- 作用域
- 生存期
- 定义与单一定义规则(ODR)
- 名字查找
- 有限定的名字查找
- 无限定的名字查找
- 如同规则
- 未定义行为
- 翻译阶段
- 常量表达式
- 赋值运算符
- 算术运算符
- 逻辑运算符
- 成员访问运算符
- 其他运算符
- sizeof 运算符
- typeid 运算符
- 指针声明
- 数组声明
- 语言链接
- 详述类型说明符
- 默认实参
- 变长实参
- 实参依赖查找
- 重载决议
- 重载函数的地址
- 注入类名
- 非静态数据成员
- 非静态成员函数
- 嵌套类
- 派生类
- 空基类优化
- 抽象类
- 位域
- 转换构造函数
- 成员模板
- 模板实参推导
- 部分模板特化
- sizeof... 运算符
- 待决名
- 函数 try 块
- 扩充命名空间 std
- 字母缩写
- RAII
- 三/五/零之法则
- PImpl
- 零开销原则
- 类型
- 隐式转换
- 注释
- C++ 关键词
- 预处理器
- C++ 标准库头文件
- 具名要求
- 功能特性测试 (C++20)
- 工具库
- 类型支持(基本类型、RTTI、类型特性)
- 概念库 (C++20)
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 容器库
- 迭代器库
- 范围库 (C++20)
- 算法库
- 数值库
- 输入/输出库
- 文件系统库
- 本地化库
- 正则表达式库
- 原子操作库
- 线程支持库
- 实验性 C++ 特性
- 有用的资源
- 索引
- std 符号索引
- 协程支持 (C++20)
- C++ 关键词
模板
模板是定义下列之一的 C++ 实体:
模板以一或多个模板形参参数化,形参有三种:类型模板形参、非类型模板形参和模板模板形参。
当提供了模板实参,或仅对于函数和类 (C++17 起)模板,当模板实参被推导出时,它们替换各模板形参,以获得模板的一个特化(specialization),即一个特定类型或一个特定函数左值。特化亦可显式提供:对类和函数模板都允许全特化,只允许对类模板部分特化。
在要求完整对象类型的语境中引用某个类模板特化时,或在要求函数定义存在的语境中引用某个函数模板特化时,除非模板已经被显式特化或显式实例化,否则模板即被实例化(instantiate)(它的代码被实际编译)。类模板的实例化不会实例化其任何成员函数,除非它们也被使用。在连接时,不同翻译单元生成的相同实例被合并。
模板的定义必须在隐式实例化点可见,这就是为何模板库通常都在头文件中提供所有模板定义的原因(例如大多数 boost 库仅有头文件)
语法
template < 形参列表 > requires-子句(C++20)(可选) 声明
|
(1) | ||||||||
export template < 形参列表 > 声明
|
(2) | (C++11 前) | |||||||
template < 形参列表 > concept 概念名 = 制约表达式 ;
|
(3) | (C++20 起) | |||||||
声明 | - | 类(包括 struct 和 union),成员类或成员枚举类型,函数或成员函数,命名空间作用域的静态数据成员,变量或类作用域的静态数据成员, (C++14 起)或别名模板 (C++11 起)的声明。它亦可定义模板特化。 |
形参列表 | - | 非空的模板形参的逗号分隔列表,其中每项是非类型形参、类型形参、模板形参或任何这些的形参包之一。 |
概念名 制约表达式 |
- | 见制约与概念 (C++20 起) |
|
(C++11 前) |
模板形参列表可以后随一个可选的 requires-子句,它指定各模板实参上的制约。 |
(C++20 起) |
本节未完成 原因:核心语法,模板形参,以及实例化,带出 class_template 和 function_template 间的公共内容 |
模板标识
模板名 < 形参列表 >
|
|||||||||
模板名 | - | 或为指名模板的标识符(该情况下称之为 "简单模板标识" ),或为重载运算符模板或用户定义字面量模板的名字。 |
指名模板特化的 简单模板标识 指名一个类。
指名别名模版特化的 模板标识 指名一个类型。
指名函数模板特化的 模板标识 指名一个函数。
模板标识 仅当符合下列条件才合法
- 实参数量不多于形参,或有形参是模板形参包,
- 每个无默认模板实参的不可推导的非包形参都有一个实参,
- 每个模板实参都与对应的模板形参相匹配,
- 替换每个模板实参到其后续模板形参(若存在)中均成功,而且
- (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 起) |
模板化实体
模板化实体(某些资料称之为 "temploid")是任何定义(或对于 lambda-表达式 为创建)于模板定义内的实体。下列所有实体都是模板化实体:
- 类/函数/变量 (C++14 起)模板
- 概念 (C++20 起)
- 模板化实体的成员(例如类模板的非模板成员函数)
- 作为模板化实体的枚举的枚举项
- 任何模板化实体中定义或创建的实体:局部类,局部变量,友元函数,等等
- 模板化实体的声明中出现的 lambda 表达式的闭包类型
例如,以下模板中:
template<typename T> struct A { void f() {} };
函数 A::f
不是函数模板,但仍被当做是模板化的。