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++11 起)
对于变量,指定要从其初始化器自动推导出其类型。
对于函数,指定要从其 return 语句推导出其返回类型。 |
(C++14 起) |
对于非类型模板形参,指定要从实参推导出其类型。 |
(C++17 起) |
语法
auto | (1) | (C++11 起) | |||||||
decltype(auto) | (2) | (C++14 起) | |||||||
类型制约 auto | (3) | (C++20 起) | |||||||
类型制约 decltype(auto) | (4) | (C++20 起) | |||||||
类型制约 | - | 概念名,可以有限定,可以后随 <> 包围的模板实参列表 |
1,3) 用模板实参推导的规则推导类型。
占位符 auto 可伴随如 const 或 & 这样的修饰符,它们参与类型推导。占位符 decltype(auto) 必须是被声明类型的唯一组分。 (C++14 起)
解释
占位符类型说明符可出现于下列语境:
- 变量的类型说明符中:auto x = expr;。从初始化器推导类型。
若占位符类型说明符为auto
或 类型制约auto
(C++20 起),则采用从函数调用进行模板实参推导的规则,从初始化器推导变量的类型(细节见其他语境)。
例如,给定 const auto& i = expr;,则i
的类型恰是某个虚构模板 template<class U> void f(const U& u) 中参数u
的类型(假如函数调用 f(expr) 通过编译)。因此,取决于初始化器,auto&& 可被推导成左值引用或右值引用类型,这被用于基于范围的 for 循环。
若占位符类型说明符为
decltype(auto)
或 类型制约decltype(auto)
(C++20 起),则推导出的类型为decltype(expr)
,其中expr
是初始化器。(C++14 起) 若用占位符类型说明符声明多个变量,则推导出的类型必须互相匹配。例如,声明 auto i = 0, d = 0.0; 非良构,而声明 auto i = 0, *p = &i; 良构并将
auto
推导为 int。 - new 表达式中的类型标识。从初始化器推导类型。对于
new T init
(其中 T 含占位符类型,而 init 是带括号的初始化器或带花括号的初始化器列表),如同在虚设的声明 T x init; 中对变量 x 一般推导 T 的类型。 - (C++14 起) 函数或 lambda 表达式的返回类型中:auto& f();。从其未弃用的 (C++17 起) return 语句的操作数推导返回类型。
见返回类型推导。 - (C++17 起) 非类型模板形参的形参声明中:template<auto I> struct A;。从对应的实参推导其类型。
此外,
|
(C++14 起) |
若 类型制约 存在,令
|
(C++20 起) |
注解
C++11 之前,auto 具有存储期说明符的语义。
不允许在一个声明中混合 auto
的变量和函数,如 auto f() -> int, i = 0;。
auto 说明符亦可用于后随尾随返回类型的函数声明符,该情况下返回类型为其尾随返回类型(它也可以是占位符类型)。
auto (*p)() -> int; // 声明指向返回 int 的函数的指针 auto (*q)() -> auto = p; // 声明 q 为指向返回 T 的函数的指针 // 其中 T 从 p 的类型推导
auto 说明符亦可用于结构化绑定声明。 |
(C++17 起) |
auto 关键词亦可用于嵌套名说明符。形如 auto:: 的嵌套名说明符是一个占位符,其将遵循受制约类型占位符的推导规则被替换为某个类或枚举类型。 |
(概念 TS) |
示例
运行此代码
#include <iostream> #include <utility> template<class T, class U> auto add(T t, U u) { return t + u; } // 返回类型是 operator+(T, U) 的类型 // 在其所调用的函数返回引用的情况下 // 函数调用的完美转发必须用 decltype(auto) template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); } template<auto n> // C++17 auto 形参声明 auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能从花括号初始化器列表推导 { return {n, n}; } int main() { auto a = 1 + 2; // a 的类型是 int auto b = add(1, 1.2); // b 的类型是 double static_assert(std::is_same_v<decltype(a), int>); static_assert(std::is_same_v<decltype(b), double>); auto c0 = a; // c0 的类型是 int,保有 a 的副本 decltype(auto) c1 = a; // c1 的类型是 int,保有 a 的副本 decltype(auto) c2 = (a); // c2 的类型是 int&,为 a 的别名 std::cout << "a, before modification through c2 = " << a << '\n'; ++c2; std::cout << "a, after modification through c2 = " << a << '\n'; auto [v, w] = f<0>(); // 结构化绑定声明 auto d = {1, 2}; // OK:d 的类型是 std::initializer_list<int> auto n = {5}; // OK:n 的类型是 std::initializer_list<int> // auto e{1, 2}; // C++17 起错误,之前为 std::initializer_list<int> auto m{5}; // OK:C++17 起 m 的类型为 int,之前为 initializer_list<int> // decltype(auto) z = { 1, 2 } // 错误:{1, 2} 不是表达式 // auto 常用于无名类型,例如 lambda 表达式的类型 auto lambda = [](int x) { return x + 3; }; // auto int x; // 于 C++98 合法,C++11 起错误 // auto x; // 于 C 合法,于 C++ 错误 }
可能的输出:
a, before modification through c2 = 3 a, after modification through c2 = 4