更改常量表达式中联合的活动成员
Changing active member of union in constant expressions
使用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.
实例
1.)是否可以在常量表达式中更改union
的活动成员?
我试图销毁活动成员,但这是不允许的,因为销毁程序通常不是constexpr
。此外,我尝试使用放置operator new
(::new (&u.b) B{2};
),但也未成功。常量表达式中也不允许使用reinterpret_cast
。更改公共初始子序列的成员也被禁止。
2.)有没有办法使可变的(在改变主动替换类型的意义上)字面上类似于boost::variant
的类型?如果可能的话,它的存储空间看起来怎么样?
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());
实例
因此,对于普通可复制类型的文字类型variant
,转换赋值运算符将是template< typename T > constexpr variant & operator = (T && x) { return *this = variant(std::forward< T >(x)); }
。
免责声明:"活动"在P0137R0中定义。
有可能在常量中更改工会的活跃成员吗表达式?
不直接,因为禁止修改非活动成员-[expr.const]/(2.8):
--左值到右值的转换(4.1)或修改(5.18、5.2.6、5.2.7),5.3.2)应用于glvalue,该glvalue指的是并集的非活动成员或其子对象;
然而,这种措辞似乎有缺陷,因为确实可以通过分配另一个工会对象来"修改"非活跃成员,如您的示例所示。事实上,拷贝分配操作符执行底层字节和活动成员内部信息的拷贝:
联合
X
副本的隐式定义的副本分配运算符CCD_ 19的对象表示(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
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 助记符和指向成员语法的指针
- 使用 std::launder 从指向非活动工会成员的指针获取指向活动工会成员的指针?
- 如何保持异步函数中使用成员的shared_ptr对象的活动状态?
- 使用 std::launder 从指向非活动对象的指针获取指向活动对象成员的指针?
- 基本派生的类成员覆盖.挑战活动11.3
- 在C++的联合中显式设置活动成员
- 正在使用reinterpret_cast(在非活动成员中)强制转换为联合 UB 的活动成员
- 只有当c++中有活动的东西时,才有一个额外的数据成员
- 访问非活动的联合成员和未定义的行为
- 对对象的数据成员的shared_ptr是否使数据成员在对象的生存期之后保持活动状态
- 访问联合中相同类型的非活动成员
- 松弛常量表达式中并集的非活动成员的左值到右值转换的解决方法
- 更改常量表达式中联合的活动成员
- 将非活动std::unique_ptr数据成员交换为联合
- 正在读取与活动联盟成员相同类型的非活动联盟成员明确定义
- CPP 私有数据成员SDL_Rect非活动状态