在常量表达式中更改union的活动成员 [英] Changing active member of union in constant expressions

查看:202
本文介绍了在常量表达式中更改union的活动成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 constexpr 联合我发现,我不能更改 union constexpr 中。只有一个例外: 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 {}; //从这里产生错误
return true;
}
static_assert(f());

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

  main.cpp:23:15:error:static_assert表达式不是一个整数常数表达式
static_assert(f());
^ ~~
main.cpp:20:11:注意:在常量表达式中不允许赋给成员'b'与活动成员'a'的联合
ub = B { };
^
main.cpp:20:9:note:在调用'& u.b-> operator =(B {})'
u.b = B {};
^
main.cpp:23:15:注意:在调用'f()'
static_assert(f());
^
生成了1个错误。

LIVE EXAMPLE



1。)是否可以更改 union 在常量表达式中?



我试图破坏活动成员,但是不允许,因为析构函数不是 constexpr 一般。我也尝试使用 operator new :: new(& ub)B {2}; 但也不成功。 reinterpret_cast 也不允许在常量表达式中。



2)有没有办法使可变(在改变活动的替代类型的意义上)文字 boost :: variant -like类型?如果可能,它的存储看起来像什么?



3。)是未定义的行为,使分配给 union 的可复制分配类型在运行时?使用放置 operator new 构建非重要类型 union 的非活动成员是未定义的行为在运行时



ADDITIONAL:



类型 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 {}; //检查活动成员是B
a = b;
a = B {}; //活动成员是B!
return true;
}
static_assert(f());

LIVE EXAMPLE



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

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0137r0.htmlrel =nofollow> P0137R0 。


是否可以更改常量
表达式中的联合的活动成员?


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


- 应用于引用非活动成员的glvalue的一个左值到右值转换(4.1)或修改(5.18,5.2.6,
5.3.2)

但是,这个措辞似乎有缺陷,因为它确实可能修改非活动成员通过分配另一个联合对象,如您的示例中所示。事实上,拷贝赋值运算符执行底层字节的拷贝和关于活动成员的内部信息:


隐式定义的拷贝 X 的对象表示(3.9)。 X







是未定义的行为,
在运行时可以拷贝分配类型的联合?


这对于一个简单的可拷贝类类型的对象来说可能很好,因为那些有简单的析构函数和复制构造函数/赋值运算符。虽然不太详细,但 CWG#1116 似乎暗示它的目的是工作:


我们从不说什么联合的活动成员,如何可以
改变,等等。该标准不清楚以下
是否有效:

  union U {int a;短b } u = {0}; 
int x = u.a; //可能这是好的,但我们从不说a是活动成员
u.b = 0; //不清楚这是否有效



Playing with constexpr and union I found out, that I can't change active member of an union in constexpr. Just one exception: union of empty classes.

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?

I tried to destruct active member, but it is not allowed, due to destructors are not constexpr in general. Also I tried to use placement operator new (::new (&u.b) B{2};), but also unusccessfull. reinterpret_cast also not allowed in constant expressions. 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? 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? 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?

ADDITIONAL:

I can change entire literal type union, but not its non-active member:

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)); }.

解决方案

Disclaimer: "active" is defined in P0137R0.

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

Not directly, since modifying a non-active member is prohibited - [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;

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.


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:

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

这篇关于在常量表达式中更改union的活动成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆