Placeholder type specifiers (since C++11)
占位类型说明符指定一个 占位类型 ,该类型稍后将被替换,通常通过从 初始化器 推导得出。
目录 |
语法
类型约束
(可选)
auto
|
(1) | ||||||||
类型约束
(可选)
decltype(auto)
|
(2) | (自 C++14 起) | |||||||
| 类型约束 | - |
(自 C++20 起)
一个
概念
名称,可选择性地限定,可选择性地后跟用
<>
括起来的模板实参列表
|
占位符
auto
可以伴随修饰符,例如
const
或
&
,这些修饰符将参与类型推导。
占位符
decltype
(
auto
)
必须是声明类型的唯一组成部分。
(C++14 起)
|
若存在
类型约束
,令
若约束表达式无效或返回 false ,则推导失败。 |
(since C++20) |
说明
占位符类型说明符可能出现在以下语境中:
参数声明在下列参数声明中,被声明参数的类型可采用语法 (1) :
|
(C++14 起) |
|
(C++17 起) |
| (C++20 起) |
函数声明
占位符类型可以出现在包含尾随返回类型的 函数声明符 的 声明说明符 中。
| (since C++14) |
auto f() -> int; // 正确:f 返回 int 类型 auto g() { return 0.0; } // C++14 起正确:g 返回 double 类型 auto h(); // C++14 起正确:h 的返回类型将在其定义时推导
变量声明
使用占位类型声明的变量类型由其 初始化器 推导得出。这种用法在变量的初始化声明中是被允许的。
占位符类型仅能作为声明说明符序列中的 声明说明符 之一出现,或作为尾随返回类型中的类型说明符之一出现,该尾随返回类型指定了替换此类声明说明符的类型。在这种情况下,声明必须至少声明一个变量,且每个变量必须具有非空的初始化器。
// 声明说明符中的 “auto” auto x = 5; // 正确:x 的类型为 int const auto *v = &x, u = 6; // 正确:v 的类型为 const int*,u 的类型为 const int static auto y = 0.0; // 正确:y 的类型为 double auto f() -> int; auto (*fp)() -> auto = f; // 正确:尾随返回类型中的 “auto” // 可从 f 推导得出
结构化绑定声明auto 说明符可用于 结构化绑定 声明。 |
(since C++17) |
new 表达式
占位符类型可用于 new 表达式 的类型标识中的类型说明符序列。在此类类型标识中,占位符类型必须作为类型说明符序列中的一个类型说明符出现,或者作为指定替换该类型说明符的类型的尾随返回类型出现。
函数式转型auto 类型说明符可用作 函数式转型 的类型说明符。 |
(since C++23) |
注释
在C++11之前, auto 具有 存储期说明符 的语义。
在未明确说明的上下文中使用占位符类型的程序是不符合规范的。
如果声明声明了多个实体,且声明说明符序列使用了占位符类型,则当满足以下任一条件时程序非良构:
- 部分声明的实体并非变量。
- 替换占位符类型的类型在每次推导中并不相同。
auto f() -> int, i = 0; // 错误:使用“auto”同时声明函数和变量 auto a = 5, b = {1, 2}; // 错误:“auto”推导出不同类型
如果表达式引用了具有未替换占位符类型的函数或变量,则程序是非良构的。
auto v = 1; auto l = [&] { v++; return l;// 错误:l的占位符类型未被替换 }; std::function<void()> p = [&] { v++; return p;// 正确 };
|
auto 关键字也可用于嵌套名称说明符。形式为 auto :: 的嵌套名称说明符是一个占位符,将根据 受约束类型 占位符推导规则替换为类或枚举类型。 |
(concepts TS) |
| 功能测试宏 | 值 | 标准 | 功能 |
|---|---|---|---|
__cpp_decltype_auto
|
201304L
|
(C++14) | decltype ( auto ) |
关键词
示例
#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 << "通过 c2 修改前, a = " << a << '\n'; ++c2; std::cout << "通过 c2 修改后, a = " << a << '\n'; auto [v, w] = f<0>(); // 结构化绑定声明 auto d = {1, 2}; // 正确:d 的类型是 std::initializer_list<int> auto n = {5}; // 正确:n 的类型是 std::initializer_list<int> // auto e{1, 2}; // 错误:根据 DR n3922,之前是 std::initializer_list<int> auto m{5}; // 正确:根据 DR n3922,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++ 中错误 [](...){}(c0, c1, v, w, d, n, m, lambda); // 抑制“未使用变量”警告 }
可能的输出:
通过 c2 修改前, a = 3 通过 c2 修改后, a = 4
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 适用版本 | 发布时行为 | 正确行为 |
|---|---|---|---|
| CWG 1265 | C++11 | auto 说明符可用于在一条声明语句中同时声明带尾随返回类型的函数和定义变量 | 已禁止 |
| CWG 1346 | C++11 | 带括号的表达式列表不能赋值给 auto 变量 | 已允许 |
| CWG 1347 | C++11 |
使用
auto
说明符的声明可分别定义类型为
T
和
std::
initializer_list
<
T
>
的两个变量
|
已禁止 |
| CWG 1852 | C++14 | decltype ( auto ) 中的 auto 说明符也是占位符 |
在此情况下
不是占位符 |
| CWG 1892 | C++11 | 函数指针类型标识的返回类型可以是 auto | 已禁止 |
| CWG 2476 | C++11 |
CWG 1892
的解决方案禁止了
从初始化器推导函数指针变量的返回类型 |
已允许 |
| N3922 | C++11 | auto 的直接列表初始化推导为 std::initializer_list |
多元素时非良构,
单元素时推导元素类型 |
参考文献
- C++23 标准 (ISO/IEC 14882:2024):
-
- 9.2.9.6 占位类型说明符 [dcl.spec.auto]
- C++20 标准 (ISO/IEC 14882:2020):
-
- 9.2.8.5 占位类型说明符 [dcl.spec.auto]
- C++17 标准 (ISO/IEC 14882:2017):
-
-
10.1.7.4
auto说明符 [dcl.spec.auto]
-
10.1.7.4
- C++14 标准 (ISO/IEC 14882:2014):
-
-
7.1.6.4
autospecifier [dcl.spec.auto]
-
7.1.6.4
- C++11 标准 (ISO/IEC 14882:2011):
-
-
7.1.6.4
auto说明符 [dcl.spec.auto]
-
7.1.6.4