C 就像一个不断成长的巨人,一方面不断的吸收各种优秀的设计思想,另一方面也在自身也在不断地进行优化,从开始到现在,C 已经发布了多个版本,每次版本的发布的时候都会给我们带来惊喜。目前C 23已经落地,本文要说的一个新的特性也是23版本中新增的,针对编译的优化委员会也是一直不遗余力,每发布一个版本,都会有相应的改进。
一、来龙去脉
C 诞生之日起使用的const关键字声明一个常量,随后在C 11版本中又引入了constexpr 关键字,主要功能是声明一个编译时常量表达式(constant expression)。它被用于变量、函数以及构造函数中,并且在编译阶段就可以参与计算。在C 17版本中又对该关键字的功能进行了扩充,提供了if constexpr表达式,是指在编译阶段可以可以进行条件编译,并根据结果选择可以编译或者不编译哪些代码块。C 20中,标准委员会又引入了两个关键字consteval and constinit。它们同时被C 20引入,其中,consteval 表示编译阶段可以求值的函数,constinit 则用于指定一个全局或静态变量的初始化行为。和与const 关键字类似却更加严格,它严格要求变量必须通过编译时的常量表达式初始化,并且只能被初始化一次。
if consteval也经常用如下表示consteval if。其后面可以有表达式也可以没有,如果没有表达式,则它本身可以参与条件判断,如下代码所示:
代码语言:javascript复制if !consteval {
Test_0();
} else {
Test_1();
}
// 和上面一样
if consteval {
Test_1();
} else {
Test_0();
}
如上,上述代码执行的逻辑和顺序是一样的。风格和我们之前的if...else 控制语句一样。当然。在if consteval 一样,if后面也可以跟一个返回值是consteval关键字修饰的函数,代码如下所示:
代码语言:javascript复制consteval bool isPositive(int num) {
return num > 0;
}
int main() {
int num;
std::cout << "输入一个数: ";
std::cin >> num;
consteval if (isPositive(num)) {
std::cout << "正数." << std::endl;
} else {
std::cout << "非正数." << std::endl;
}
return 0;
}
上面的代码会根据函数返回结果输出不同信息。使用过程中需要注意的是consteval if语句内部的条件表达式必须是在编译时期可计算的常量表达式。如果条件表达式在编译时期无法确定,将导致编译错误。正因为这个限制,if coneval也被用来做编译间的语法检查。
二、编译期的语法检查
先来看下面这段代码,它的功能是在编译期间检查字符串的长度是否超出了阈值。
代码语言:javascript复制consteval bool checkStringLength(const std::string& str, uint maxLength) {
if (str.length() > maxLength) {
return false;
}
return true;
}
int main() {,
constexpr int maxLength = 10;
if (checkStringLength("Hello,world", maxLength)) {
std::cout << "字符串长度在正常范围内." << std::endl;
}
return 0;
}
如上代码所示,上述代码在编译时会产生一个编译错误,如果想要编译正常输出一个正常的结果需要按照checkStringLength要求传入参数。
三、总结
本文主要介绍了C 23版本中提供的一个新的特性,需要注意的是coneval函数是在编译期执行的,因此它的结果是在编译期计算出来,这也就要求编码人员在使用时就需要明确它能够在编译期进行计算,否则将产生错误。