对《C++编程原理与实践》中constexpr示例正确性的疑问及修正探讨
你的判断完全正确,书中示例确实存在错误
首先,我们来明确C++标准中关于constexpr变量初始化的核心规则:
- 要初始化一个
constexpr变量,其初始化器必须是常量表达式。 - 若要在常量表达式中使用一个对象,该对象必须是
constexpr声明的,或者是const类型且由常量表达式初始化的(对于自动变量而言,仅const还不够,必须确保其值在编译期完全可知)。
回到书中的示例代码:
void user(Point p1) {
Point p2 {10,10};
Point p3 = scale(p1); // OK: p3 == {100,8}; 运行时求值可行
constexpr Point p4 = scale(p2); // p4 == {100,8}
constexpr Point p5 = scale(p1); // error: scale(p1)不是常量表达式
constexpr Point p6 = scale(p2); // p6 == {100,8}
// . . .
}
这里的问题出在p2的声明上:它只是一个普通的自动变量,既没有constexpr也没有const修饰。哪怕它是用字面量10,10初始化的,它的存储属于运行时范畴,其值无法被常量表达式的编译期求值过程访问。因此constexpr Point p4 = scale(p2);和constexpr Point p6 = scale(p2);这两行代码必然会触发编译错误,和p5的错误原因本质一致——scale(p2)无法在编译时完成求值。
修正后的正确代码
void user(Point p1) { constexpr Point p2 {10,10}; // 必须添加constexpr修饰 Point p3 = scale(p1); // OK: 运行时求值可行 constexpr Point p4 = scale(p2); // OK: 编译期求值 constexpr Point p5 = scale(p1); // error: scale(p1)不是常量表达式 constexpr Point p6 = scale(p2); // OK: 编译期求值 // . . . }
这种情况大概率是书中的笔误,作为C++的设计者,Stroustrup不可能不清楚常量表达式的规则,应该是编写示例时遗漏了constexpr修饰符。
内容的提问来源于stack exchange,提问作者Maestro
相关产品推荐
相关产品推荐

