常量表达式上下文中的对象修改规则疑问
C++常量表达式对象修改规则的理解误区
struct S { constexpr S(){}; constexpr S(const S &r) { *this = r; }; constexpr S &operator=(const S &) { return *this; }; }; int main() { S s1{}; constexpr S s2 = s1; // 编译器判定合法 }
上述程序是合法的,但你认为它应该违反常量表达式规则。根据C++标准条款[expr.const]/(5.16):
表达式
E是核心常量表达式,除非其按照抽象机规则求值时出现下列情况之一:
- [...]
- (5.16) 对象的修改,除非修改的是字面类型的非易失性左值,且该左值指代的非易失性对象的生存期始于
E的求值过程中;- [...]
你的理解误区在于搞错了核心常量表达式E的范围,以及被修改的对象是谁:
- 这里的
E不是s1,而是初始化constexpr对象s2的整个表达式——也就是拷贝构造函数的调用过程。 - 拷贝构造函数里的
*this = r;修改的是正在构造的s2(*this指代的是s2),而不是s1。s2的生存期正是在这个常量表达式E的求值过程中开始的,完全满足条款中的例外条件。 s1在整个过程中只是被读取,并没有被修改,所以根本不触发[expr.const]/(5.16)的禁止条件。
简单来说,你误以为修改的是s1,但实际修改的是新对象s2,而s2的生存期始于常量表达式求值期间,符合规则,因此程序合法。
内容的提问来源于stack exchange,提问作者mada
相关产品推荐
相关产品推荐

