c++ - 在常量表达式中更改 union 的事件成员

标签 c++ c++14 unions constexpr variant

constexprunion我发现,我无法更改 union 的活跃成员在 constexpr .只有一个异常(exception):union空类。

constexpr bool t()
{
    struct A {};
    struct B {};
    union U { A a; B b; } u{};
    u.a = A{};
    u.b = B{};
    return true;
}
static_assert(t());

constexpr bool f()
{
    struct A { char c; };
    struct B { char c; };
    union U { A a; B b; } u{};
    u.a = A{};
    u.b = B{}; // error originating from here
    return true;
}
static_assert(f());

第一个函数可能会产生常量表达式。但是第二个不能。硬错误说:

main.cpp:23:15: error: static_assert expression is not an integral constant expression
static_assert(f());
              ^~~
main.cpp:20:11: note: assignment to member 'b' of union with active member 'a' is not allowed in a constant expression
    u.b = B{};
          ^
main.cpp:20:9: note: in call to '&u.b->operator=(B{})'
    u.b = B{};
        ^
main.cpp:23:15: note: in call to 'f()'
static_assert(f());
              ^
1 error generated.

LIVE EXAMPLE

1.) 是否可以更改 union 的活跃成员?在常量表达式中?

我试图销毁事件成员,但不允许这样做,因为析构函数不是 constexpr一般来说。我也尝试使用放置 operator new ( ::new (&u.b) B{2}; ),但也很不方便。 reinterpret_cast也不允许出现在常量表达式中。也禁止改变公共(public)初始子序列的成员。

2.) 有没有办法使可变(在改变事件替代类型的意义上)文字 boost::variant -喜欢的类型?如果可能的话,它的存储看起来如何?

3.) 对 union 的非事件成员进行赋值是未定义的行为吗? 在运行时的普通复制赋值类型?构造 union 的非事件成员是否为未定义行为使用放置的平凡可复制类型 operator new避免在运行时初步销毁事件成员?

附加:

我可以改变整个文字类型 union ,但不是其非活跃成员:

constexpr
bool
f()
{
    struct A { char c; };
    struct B { char c; };
    union U 
    {
        A a; B b; 
        constexpr U(A _a) : a(_a) { ; }  
        constexpr U(B _b) : b(_b) { ; }  
    };
    U a(A{});
    a.a = A{}; // check active member is A
    U b(B{});
    b.b = B{}; // check active member is B
    a = b;
    a = B{}; // active member is B!
    return true;
}
static_assert(f());

LIVE EXAMPLE

因此对于文字类型 variant普通可复制类型的转换赋值运算符将是 template< typename T > constexpr variant & operator = (T && x) { return *this = variant(std::forward< T >(x)); } .

最佳答案

免责声明:“事件”在 P0137R0 中定义.

Is it possible to change active member of union in constant expressions?

不直接,因为禁止修改非事件成员 - [expr.const]/(2.8):

— an lvalue-to-rvalue conversion (4.1) or modification (5.18, 5.2.6, 5.3.2) that is applied to a glvalue that refers to a non-active member of a union or a subobject thereof;

但是,这种措辞似乎有缺陷,因为确实可以通过分配另一个 union 对象来“修改”非事件成员,如您的示例所示。实际上,复制赋值运算符执行底层字节和有关事件成员的内部信息的复制:

The implicitly-defined copy assignment operator for a union X copies the object representation (3.9) of X.


Is it undefined behaviour to make assignment to non-active members of union of trivially copy-assignable types at runtime?

这对于普通可复制类类型的对象来说可能没问题,因为它们具有普通的析构函数和复制构造函数/赋值运算符。尽管未指定,CWG #1116似乎暗示它是为了工作:

We never say what the active member of a union is, how it can be changed, and so on. The Standard doesn't make clear whether the following is valid:

union U { int a; short b; } u = { 0 };
int x = u.a; // presumably this is OK, but we never say that a is the active member
u.b = 0;     // not clear whether this is valid

关于c++ - 在常量表达式中更改 union 的事件成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33936295/

相关文章:

java - 互斥锁与彼得森算法?

c - 与 union 产出作斗争

c++ - 在 Qt 设计器中叠加小部件

c++ - 在其他实现文件中包含实现文件有什么用?

c++ - C 和 C++ 中 arr[i] = i++ 和 i = i + 1 语句的行为

c++ - 从整型常量表达式转换为空指针

c++ - 如何区分ascii值和数字?

c - 平方根 union 和位移位

c - 如何在不命名的情况下访问 union 成员?

c++ - 关于正确使用智能指针的问题