为什么我可以在constexpr函数中修改const_cast-ed对象?
我一直以为:
- 写入
const_casted 变量是 UB - constexpr 中不允许使用 UB
所以我很困惑为什么这段代码会编译:
constexpr int fn(){
int v = 42;
return [v]() {
const_cast<int&>(v)+=5;
return v;
}();
}
static constexpr auto val = fn();
int main() {
return val;
}
注意:我知道没有理由不允许这样做,因为结果应该是显而易见的,我对为什么允许这样做的法律解释更感兴趣。
回答
这部分是真的:
constexpr 中不允许使用 UB
这部分不是:
写入
const_cast-ed 变量是 UB
实际规则是,来自[dcl.type.cv]/4:
任何在其生命周期 ([basic.life]) 期间修改 ([expr.ass], [expr.post.incr], [expr.pre.incr]) 的尝试都会导致 const 对象 ([basic.type.qualifier])在未定义的行为中。
请注意,相关部分是对象是否为const,而不是您到达它所采用的任何路径是否为const。在这种情况下,v不是const对象,也不是复制时在 lambda 中创建的对象。
但是,如果您声明v为const,那么在 lambda 中声明的那个也将被声明为const,因此尝试修改它将是未定义的行为。结果,您的代码将不再编译。
THE END
二维码