简体   繁体   English

在常量表达式中更改union的活动成员

[英]Changing active member of union in constant expressions

Playing with constexpr and union I found out, that I can't change active member of an union in constexpr . constexprunion一起玩,我发现,我无法在constexpr更改union活跃成员。 Just one exception: union of empty classes. 只有一个例外:空类的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());

First function may produce constant expression. 第一个函数可以产生常量表达。 But the second can't. 但第二个不能。 Hard error says: 硬错误说:

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.) Is it possible to change active member of union in constant expressions? 1.)是否有可能在常量表达式中更改union活动成员?

I tried to destruct active member, but it is not allowed, due to destructors are not constexpr in general. 我试图破坏活动成员,但是不允许,因为析构函数通常不是constexpr Also I tried to use placement operator new ( ::new (&u.b) B{2}; ), but also unusccessfull. 此外,我尝试使用placement operator new::new (&u.b) B{2}; ),但也尝试使用。 reinterpret_cast also not allowed in constant expressions. reinterpret_cast也不允许在常量表达式中。 Altering members of common initial subsequence prohibited too. 也禁止改变共同初始后续成员的成员。

2.) Are there a ways to make mutable (in sense of changing active alternative type) literal boost::variant -like type? 2.)有没有办法使boost::variant (在改变主动替代类型的意义上)文字boost::variant -like类型? How looks like its storage if it possible? 如果可能,它的存储看起来如何?

3.) Is it undefined behaviour to make assignment to non-active members of union of trivially copy-assignable types at runtime ? 3.)是否在运行时为非活动的简单复制可分配类型的union成员赋值是未定义的行为? Is it undefined behaviour to construct non-active member of union of trivially-copyable types using placement operator new avoiding preliminary destruction of active member at runtime ? 它是不确定的行为来构建的非活跃成员union使用放置平凡的,可复制的类型的operator new避免在运行时活跃成员的初步破坏?

ADDITIONAL: 额外:

I can change entire literal type union , but not its non-active member: 我可以更改整个文字类型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 现场例子

Therefore for literal type variant of trivially copyable types conversion assignment operator would be template< typename T > constexpr variant & operator = (T && x) { return *this = variant(std::forward< T >(x)); } 因此,对于平凡可复制类型的文字类型variant ,转换赋值运算符将是template< typename T > constexpr variant & operator = (T && x) { return *this = variant(std::forward< T >(x)); } template< typename T > constexpr variant & operator = (T && x) { return *this = variant(std::forward< T >(x)); } . template< typename T > constexpr variant & operator = (T && x) { return *this = variant(std::forward< T >(x)); }

Disclaimer: "active" is defined in P0137R0 . 免责声明:“有效”在P0137R0中定义。

Is it possible to change active member of union in constant expressions? 是否可以在常量表达式中更改union的活动成员?

Not directly, since modifying a non-active member is prohibited - [expr.const]/(2.8): 不直接,因为禁止修改非活动成员 - [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; - 应用于glvalue的左值到右值转换(4.1)或修改( 5.18,5.2.6,5.3.2 ,该glvalue引用联合或其子对象的非活动成员;

However, this wording seems defective, since it's indeed possible to "modify" a non-active member by assignment of another union object as shown in your example. 但是,这种措辞似乎有缺陷,因为确实可以通过分配另一个联合对象来“修改”非活动成员,如示例所示。 In fact, the copy assignment operator performs a copy of the underlying bytes and the internal information about the active member: 实际上,复制赋值运算符执行基础字节的副本和有关活动成员的内部信息:

The implicitly-defined copy assignment operator for a union X copies the object representation (3.9) of X . 用于联合的隐式定义的拷贝赋值运算符X副本的对象表示(3.9) X


Is it undefined behaviour to make assignment to non-active members of union of trivially copy-assignable types at runtime? 是否未定义行为在运行时分配给非活动成员的简单复制可分配类型的联合?

That's presumably fine for objects of a trivially copyable class type, since those have trivial destructors and copy constructors/assignment operators. 这对于一个简单的可复制类类型的对象来说可能是好的,因为它们具有简单的析构函数和复制构造函数/赋值运算符。 Although underspecified, CWG #1116 seems to imply that it's intended to work: 虽然未明确,但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 = ua; // presumably this is OK, but we never say that a is the active member ub = 0; // not clear whether this is valid 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM