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

时间:2015-11-26 10:32:37

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

使用constexprunion我发现,我无法更改unionconstexpr的有效成员。只有一个例外: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也不允许使用常量表达式。也禁止改变共同初始子序列的成员。

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

1 个答案:

答案 0 :(得分:4)

免责声明:&#34;活跃&#34;在P0137R0中定义。

  

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

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

  

- 左值到右值的转换(4.1)或修改(5.18,5.2.6,   5.3.2),应用于引用联合或其子对象的非活动成员的glvalue;

然而,这个措辞似乎有缺陷,因为它确实可以修改&#34;通过分配另一个union对象的非活动成员,如示例所示。实际上,复制赋值运算符执行基础字节的副本和有关活动成员的内部信息:

  

联合X副本的隐式定义的复制赋值运算符   X的对象表示(3.9)。

  

是否定义了非活动成员的未定义行为   在运行时简单地复制可分配类型的联合?

对于一个简单的可复制类类型的对象来说,这可能是好的,因为那些具有简单的析构函数和复制构造函数/赋值运算符。虽然未说明,但CWG #1116似乎意味着它的目的是:

  

我们永远不会说联盟的活跃成员是什么,怎么可能   改变了,等等。标准没有明确是否   以下是有效的:

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