使用std::construct_at复制值切换union活跃成员是否合规?
能否通过std::construct_at复制原活跃成员的值来切换union的活跃成员?
以下是最简示例代码:
#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)...);
编译器正确性分析
根据C++标准规则:
- union的活跃成员是最后被初始化或构造的成员。示例中
u的初始活跃成员是x(因为x带有默认初始化器{0})。 std::construct_at(&u.y, u.x)的执行流程中,参数u.x的求值发生在u.y的构造操作之前——此时x仍然是union的活跃成员,读取x完全合法。- 当
placement new完成u.y的构造后,y才会成为新的活跃成员,后续读取u.y也符合规则。
Clang的错误在于错误判定:在参数u.x求值时,y已经是活跃成员。这不符合C++标准中“参数求值先于函数/构造操作执行”的顺序规则。因此GCC和MSVC的实现是正确的,Clang的拒绝行为有误。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

