C23 添加了关键字
constexpr
,可用于将对象定义为编译时常量,而不是枚举或宏。例如:
constexpr int x = 10;
constexpr int y = x+10; // Valid
switch (some_var) {
case y: // Valid
// ...
}
static int z = y; // Valid
以前只有整数常量(
sizeof()
或enum
或文字值,例如10
)或全局/static
对象的地址可以被视为编译/翻译时常量,并且可以执行一些算术运算在编译时对它们进行处理。
C23 中的
constexpr
表达式中是否可以处理任何新的操作和类型?有什么限制?
constexpr
可用于限定复合文字:
带有存储类说明符 constexpr 的复合文字是复合文字常量。复合文字常量是具有未命名对象的类型和值的常量表达式。
在 C23 之前,不支持编译时常量(甚至
static
)复合文字,即使它们的所有成员都是编译时常量:
static int x = (int){0}; // Non-portable
static int x = (constexpr int){0}; // Valid C23
struct
和 union
从结构体或联合常量开始,成员访问
运算符可用于形成命名常量 [...]。.
constexpr
可以与 struct
或 union
组合来创建编译时常量对象。可以在编译时读取成员:
constexpr struct {
int x;
} s = {10};
static int x = s.x; // Valid
这不允许编译时类型双关:
如果成员访问运算符数组
.
访问联合常量的成员,则访问的成员应与联合常量的初始值设定项初始化的成员相同。
数组下标但是这些运算符
[]
和成员访问->
运算符、地址&
和间接*
一元运算符以及指针强制转换可用于创建地址常量,但对象的值不得使用这些运算符进行访问。
可以用于生成数组成员之一的地址作为编译时常量。
功能constexpr
函数不支持。因此,在
constexpr
表达式中不能使用函数调用。不支持的操作
常量表达式不得包含赋值、递增、递减、函数调用或逗号运算符,除非它们包含在未计算的子表达式中。