关于constexpr函数调用hello(i)与hello(6)的差异技术问询
hello(i)报错而hello(6)正常? 嘿,这个问题问到点子上了——本质是constexpr变量对初始化表达式的要求,以及「普通变量」和「字面量」在编译期的本质区别。
先明确一个核心规则:
用来初始化
constexpr变量的表达式,必须是编译期就能确定结果的常量表达式。
我们拆解两种情况来看:
1. 为什么hello(i)会报错?
i是一个普通的int变量:
int i = 6;
哪怕你给它赋值了6,它的本质还是一个运行时变量——它的值存储在程序运行时的栈空间里,编译器不会把它当作「编译期就能确定的常量」。当你把i传给constexpr函数hello时,函数的参数j就不是一个编译期常量,那hello(i)的结果自然没法在编译阶段计算出来,不符合constexpr变量a1的初始化要求,所以编译器会报错。
如果把i改成constexpr int i = 6;或者const int i = 6;,hello(i)就可以正常编译了——因为此时i是编译期常量,能作为常量表达式传递给hello。
2. 为什么hello(6)能正常运行?
这里的6是整数字面量,它属于C++里天生的「常量表达式」。字面量的值不需要依赖运行时的内存存储,编译器在编译代码的时候就直接知道它的值是6,能直接计算6*12的结果(也就是72),整个hello(6)的调用就是一个编译期可计算的常量表达式,完全满足constexpr变量a2的初始化条件,所以不会报错。
你可能会疑惑:字面量没加constexpr为什么可以?其实constexpr是用来修饰变量/函数的关键字,而字面量本身就是编译期确定值的实体,不需要额外修饰就具备常量表达式的属性。
再补充看你的代码里的hello(int(6))——这里的int(6)是一个显式类型转换的常量表达式,本质和字面量6一样,编译期就能确定值,所以也能正常初始化a3。
同理,bye()用了默认参数6(字面量),bye(6)直接传字面量,都是编译期可计算的,所以a4和a6正常;而bye(i)和hello(i)一样,参数是运行时变量,所以a5报错。
内容的提问来源于stack exchange,提问作者Rick

