使用 std::construct_at 进行复制来更改联合中的活动成员

问题描述 投票:0回答:1

可以使用

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

这里哪种实现是正确的?

c++ language-lawyer c++20 union constexpr
1个回答
0
投票

CWG 2721 的决议阐明,当分配函数返回时且在评估

new
初始值设定项之前,存储被视为由
new
重用。

当存储被重用时,前一个对象的生命周期结束,并且不再活跃。

因此 Clang 是正确的。

std::construct_at
通过引用获取参数并将它们转发到
new
初始值设定项。左值到右值的转换应用于
u.x
,以便仅在初始化器求值期间获取存储的值。此时存储已被重用,
u.x
的生命周期已结束。

这可以通过写作来解决

std::construct_at(&u.y, auto(u.x));

auto v = u.x;
std::construct_at(&u.y, v);

相反。

© www.soinside.com 2019 - 2024. All rights reserved.