【问题标题】:Changing active member of union in constant expressions在常量表达式中更改联合的活动成员
【发布时间】:2015-11-26 10:32:36
【问题描述】:

与constexpr 和union 一起玩我发现,我无法更改constexpr 中union 的活动成员。只有一个例外: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-like 类型?如果可能的话,它的存储方式如何?

3.) 在运行时对union 的非活动成员进行分配是否是未定义的行为?使用放置operator new 来构造union 的普通可复制类型的非活动成员以避免在运行时 初步破坏活动成员是否是未定义的行为?

附加:

我可以更改整个文字类型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)); }。

【问题讨论】:

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


【解决方案1】:

免责声明:“活跃”在P0137R0中定义。

是否可以在常量中更改工会的活跃成员 表达式?

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

——左值到右值的转换(4.1)或修改(5.18、5.2.6、 5.3.2) 应用于指向联合或其子对象的非活动成员的泛左值;

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

联合 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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 2019-10-11
  • 2011-07-16
相关资源
最近更新 更多