常量求值阶段的所有表达式均为常量表达式吗?C++标准示例疑问
C++常量表达式相关疑问解答
先看你给出的示例代码:
constexpr int incr(int& n) { return ++n; } constexpr int g(int k) { constexpr int x = incr(k); // error: incr(k) is not a core constant // expression because lifetime of k // began outside the expression incr(k) return x; } constexpr int h(int k) { int x = incr(k); // OK: x is not required to be initialized // with a core constant expression return x; } constexpr int y = h(1); // OK: initializes y with the value 2 // h(1) is a core constant expression because // the lifetime of k begins inside the expression h(1)
疑问1:h函数中的int x = incr(k);为何在编译期求值也合法?
关键区别在于变量的类型:h里的x是普通自动变量,不是constexpr变量。
constexpr变量要求初始化表达式必须是核心常量表达式,但普通自动变量没有这个强制要求。- 当
h(1)被用来初始化constexpr int y时,整个进入编译期常量求值流程:参数k的生命周期始于h(1)的求值过程中,调用incr(k)修改的是这个生命周期在当前常量求值范围内的非volatile字面类型对象,完全符合核心常量表达式的修改规则。 - 这里
incr(k)只是用来初始化普通变量x,不需要单独满足核心常量表达式的要求——只要整个h(1)的求值过程整体符合核心常量表达式规则,就能合法完成编译期求值。
对比g函数里的constexpr int x = incr(k);,因为x是constexpr变量,必须用核心常量表达式初始化,但incr(k)修改的k的生命周期始于g的参数传递(也就是incr(k)这个表达式之外),违反了核心常量表达式的修改规则,所以报错。
疑问2:常量求值过程中的所有表达式是否都属于常量表达式?
不是。
常量求值是一个执行流程,流程里的子表达式不一定都要满足核心常量表达式的要求——只有当某个子表达式被明确要求必须是核心常量表达式时(比如初始化constexpr变量、作为constexpr模板的实参、用于static_assert的条件等),才需要符合规则。
像h函数里的incr(k),它是常量求值过程中的子表达式,但因为只是用来初始化普通自动变量,不需要单独成为核心常量表达式。只要整个h(1)的求值过程整体符合核心常量表达式的要求,就能用来初始化constexpr变量y。
内容的提问来源于stack exchange,提问作者SomeoneWithPassion
相关产品推荐
相关产品推荐

