可以通过复制前一个活跃成员的值来更改联合中的活跃成员吗std::construct_at
?
这个最小的例子
#include <memory>
constexpr int f() {
union U {
char x{0};
int y;
} u;
std::construct_at(&u.y, u.x);
return u.y;
}
static_assert( f() == 0 );
被 GCC 和 MSVC 接受,但 Clang 拒绝它并出现错误:
/opt/compiler-explorer/clang-19.1.0/bin/../include/c++/v1/__memory/construct_at.h:41:50:
note: read of member 'x' of union with active member 'y' is not allowed in a constant expression
41 | return ::new (std::__voidify(*__location)) _Tp(std::forward<_Args>(__args)...);
在线演示:https://gcc.godbolt.org/z/xrj57jroj
这里哪种实现是正确的?
CWG 2721的解决方案明确指出,
new
当分配函数返回时并且在new
初始化程序被评估之前,存储被视为已重用。当存储被重新使用时,前一个对象的生命周期就结束了,并且不再处于活动状态。
因此 Clang 是正确的。
std::construct_at
通过引用获取参数并将它们转发给new
初始化器。仅在初始化器求值期间应用左值到右值的转换,u.x
以便获取存储的值。此时存储已被重用,并且的生命周期u.x
已结束。std::construct_at
因此,在常量表达式中不允许进行该调用,而在常量表达式之外则具有未定义的行为。可以通过以下方式修复
或者
反而。