泛型选择 (C11 起)
来自cppreference.com
提供一种方式,基于控制表达式的类型,在编译时选择数个表达式之一。
目录 |
[编辑]语法
_Generic ( 控制表达式, 关联列表) | (C11 起) | ||||||||
其中 关联列表 是关联的逗号分隔列表,每项关联的语法为:
类型名: 表达式 | |||||||||
default : 表达式 | |||||||||
其中
类型名 | - | 任何并非可变修改的完整对象类型(即既非 VLA 亦非指向 VLA 的指针)。 |
控制表达式 | - | 任何表达式(除了逗号运算符),若不使用 default 关联,则其类型必须与 类型名 之一兼容 |
表达式 | - | 任何类型和值类别的表达式(除了逗号运算符) |
关联列表 中的任意二个 类型名 不能指定兼容类型。使用关键词 default 的关联只能有一个。若不使用 default,且无一 类型名 与控制表达式类型兼容,则程序无法编译。
[编辑]解释
首先,控制表达式 的类型经历左值转换。只在类型域中进行转换:它舍弃顶层 cvr 限定符和原子属性,并应用数组到指针/函数到指针变换到控制表达式的类型,而不实例化任何副效应或计算任何值。
将转换后的类型与来自关联列表中的 类型名 比较。
若其类型与各关联之一的 类型名兼容,则泛型选择的类型、值及值类别就是出现于该 类型名 冒号后的表达式的类型、值及值类别。
若无一 类型名 的类型与 控制表达式 兼容,且提供了 default 关联,则泛型的类型、值及值类别就是出现于 default :
标号后的表达式的类型、值及值类别。
[编辑]注解
决不求值 控制表达式 和未被选择的选项中的 表达式。
因为左值转换,"abc" 匹配 char* 而非 char[4],(intconst){0} 匹配 int 而非 constint。
泛型选择中的 表达式 允许任何值类别,含函数指代符及 void 表达式,而且若它受到选择,则泛型选择自身拥有相同的值类别。
C99 中引入的来自 <tgmath.h> 的泛型数学宏曾是通过编译器特定的行为实现的。 C11 所引入的泛型选择给予程序员写相似的类型依赖代码的能力。
泛型选择类似 C++ 中的重载(在编译时基于参数类型选择数个函数之一),但它在任意表达式之间选择。
[编辑]关键词
[编辑]示例
运行此代码
#include <math.h>#include <stdio.h> // tgmath.h 宏 cbrt 的可能实现#define cbrt(X) _Generic((X), \ long double: cbrtl, \ default: cbrt, \ float: cbrtf \ )(X) int main(void){double x =8.0;constfloat y =3.375;printf("cbrt(8.0) = %f\n", cbrt(x));// 选择默认的 cbrtprintf("cbrtf(3.375) = %f\n", cbrt(y));// 将 const float 转换成 float,// 然后选择 cbrtf}
输出:
cbrt(8.0) = 2.000000 cbrtf(3.375) = 1.500000
[编辑]缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
DR 481 | C11 | 未指定控制表达式是否经历左值转换 | 经历 |
[编辑]引用
- C23 标准(ISO/IEC 9899:2024):
- 6.5.1.1 Generic selection (第 TBD 页)
- C17 标准(ISO/IEC 9899:2018):
- 6.5.1.1 Generic selection (第 56-57 页)
- C11 标准(ISO/IEC 9899:2011):
- 6.5.1.1 Generic selection (第 78-79 页)
[编辑]参阅
模板的 C++ 文档 |