Ori*_*ent 5 c++ variant unions constexpr c++14
constexpr和union我一起玩,我发现我不能更改unionin的活动成员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{}; // error originating from here
return true;
}
static_assert(f());
Run Code Online (Sandbox Code Playgroud)
第一个函数可能会产生常量表达式。但是第二个不能。硬错误说:
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.
Run Code Online (Sandbox Code Playgroud)
1.)是否可以更改union常量表达式中的active成员?
我试图销毁活动成员,但由于销毁者不在constexpr一般范围内,因此是不允许的。另外,我尝试使用放置位置operator new(::new (&u.b) B{2};),但未成功。reinterpret_cast也不允许在常量表达式中使用。禁止更改共同的初始子序列的成员。
2)是否有一种方法可以使可变的(就改变有效的替代类型而言)像文字一样boost::variant的类型?如果可能的话,其存储情况如何?
3.)在运行时union对微不足道的可分配类型的非活动成员进行分配是否是未定义的行为?使用放置构造普通副本类型的非活动成员以避免运行时对活动成员的初步破坏是未定义的行为吗?unionoperator 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());
Run Code Online (Sandbox Code Playgroud)
因此,对于variant平凡可复制类型的文字类型,转换赋值运算符将为template< typename T > constexpr variant & operator = (T && x) { return *this = variant(std::forward< T >(x)); }。
免责声明:在P0137R0中定义了“活动” 。
是否可以在常量表达式中更改联合的活动成员?
不直接,因为禁止修改非活动成员-[expr.const] /(2.8):
— 应用于引用联合的非活动成员或其子对象的glvalue 的左值到右值转换(4.1)或修改( 5.18、5.2.6、5.3.2);
但是,这种措辞似乎是有缺陷的,因为确实可以通过分配另一个联合对象来“修改”非活动成员,如您的示例所示。实际上,拷贝分配操作符执行基础字节和有关活动成员的内部信息的拷贝:
联合的隐式定义的复制分配运算符
X复制的对象表示形式(3.9)X。
在运行时对琐碎的可分配类型的并集的非活动成员进行分配是未定义的行为吗?
这对于普通可复制类类型的对象可能很好,因为这些对象具有普通析构函数和复制构造函数/赋值运算符。尽管未指定,但CWG#1116似乎暗示它旨在工作:
我们永远不会说工会的活跃成员是什么,如何改变工会等等。该标准并未明确以下内容是否有效:
Run Code Online (Sandbox Code Playgroud)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