6.7.10 类型推导
IMPORTANT
C23 里的类型推导不是“任意地方都像 C++ auto 那样工作”。标准把它限制得很窄,本质上是:用 auto 声明一个带初始化器的对象,然后从初始化表达式推导对象类型。
约束
- 只要一条声明要进行类型推导,就必须包含存储类说明符
auto。
语义
- 对象定义若采用类型推导,其
init-declarator必须是:
c
direct-declarator = assignment-expression1
被声明对象的推导类型,取自初始化表达式在经历以下调整之后的类型:
- 左值转换;
- 数组到指针转换;
- 函数到指针转换。
声明说明符中若还写了限定符或属性,它们会继续附加到推导得到的类型上。
实现可以只接受最简单的直接声明符,也就是:
c
identifier1
或带属性、再外面可套平衡括号的版本。
- 如果实现接受更复杂的直接声明符形式,其行为由实现定义。
重要边界
若一条
auto声明同时又定义了结构体或联合体类型,那么行为由实现定义。标准特别提醒:初始化表达式中不能使用当前正在被推导类型的那个标识符。
原因不是“它还没赋值”,而是它的作用域要到初始化器结束后才开始。
例子
- 文件作用域中:
c
static auto a = 3.5;
auto p = &a;1
2
2
等价于:
c
static double a = 3.5;
double *p = &a;1
2
2
- 数组与指针:
c
double A[3] = { 0 };
auto pA = A;
auto qA = &A;1
2
3
2
3
这里 pA 是 double *,而 qA 是“指向整个数组的指针”。
- 它也适合捕获类型泛型调用的返回类型:
c
auto y = cos(x);1
- 在
for循环控制部分也可以使用类型推导:
c
for (auto i = j; i < 2 * j; ++i) {
/* ... */
}1
2
3
2
3
这样 i 会取得 j 经过规则调整后的类型,通常更容易保持比较两侧类型一致。