我知道我们可以访问匿名联合而不创建它的对象(没有点), 但有人可以解释一下,匿名工会在现实世界的c ++编程中有什么用?
答案 0 :(得分:6)
我主要使用联合在同一个连续存储中存储多种不同类型的元素,而不依赖于动态多态。因此,我的union的每个元素都是一个描述相应节点类型数据的结构。使用匿名联合主要提供更方便的表示法,即代替object.union_member.struct_member
,我可以写object.struct_member
,因为不管怎样,该名称中没有其他成员。
最近我使用它们的一个例子是一个有根的(主要是二进制)树,它有不同类型的节点:
struct multitree_node {
multitree_node_type type;
...
union {
node_type_1 n1;
node_type_2 n2;
...
};
};
使用此类型标记type
我能够确定要使用的联合的哪个元素。所有结构node_type_x
的大小大致相同,这就是为什么我首先使用了union(没有未使用的存储空间)。
使用C ++ 17,您可以使用std::variant
执行此操作,但目前,使用匿名联合是实现此类“多态”类型而不使用virtual
函数的便捷方式。 / p>
答案 1 :(得分:2)
这是一个真实的例子:
var date = new Date();
var date1 = new Date("#startDate").val());
var date2 = d.getDate();
您可以使用struct Point3D {
union {
struct {
float x, y, z;
};
struct {
float c[3];
};
};
};
Point3D p;
,p
,p.x
访问p.y
的x / y / z坐标。这很方便。
但有时您希望将点作为p.z
数组进行访问。您可以使用float[3]
。
注意:使用此构造是标准的未定义行为。但是,它适用于我到目前为止遇到的所有编译器。所以,如果你想使用这样的结构,请注意,这可能会在某一天破裂。
答案 2 :(得分:1)
我实际上记得我曾经遇到的一个用例。你知道比特字段吗?该标准对其在内存中的布局提供了很少的保证。如果你想将二进制数据打包成特定大小的整数,你通常最好不要自己进行逐位算术。
但是,使用联合和常见的初始序列保证,您可以将所有样板放在成员访问语法之后。因此,您的代码看起来像是使用位字段,但实际上只是将位打包到可预测的内存位置。
这是 Live Example
#include <cstdint>
#include <type_traits>
#include <climits>
#include <iostream>
template<typename UInt, std::size_t Pos, std::size_t Width>
struct BitField {
static_assert(std::is_integral<UInt>::value && std::is_unsigned<UInt>::value,
"To avoid UB, only unsigned integral type are supported");
static_assert(Width > 0 && Pos < sizeof(UInt) * CHAR_BIT && Width < sizeof(UInt) * CHAR_BIT - Pos,
"Position and/or width cannot be supported");
UInt mem;
BitField& operator=(UInt val) {
if((val & ((UInt(1) << Width) - 1)) == val) {
mem &= ~(((UInt(1) << Width) - 1) << Pos);
mem |= val << Pos;
}
// Should probably handle the error somehow
return *this;
}
operator UInt() {
return (mem >> Pos) & Width;
}
};
struct MyColor {
union {
std::uint32_t raw;
BitField<std::uint32_t, 0, 8> r;
BitField<std::uint32_t, 8, 8> g;
BitField<std::uint32_t, 16, 8> b;
};
MyColor() : raw(0) {}
};
int main() {
MyColor c;
c.r = 0xF;
c.g = 0xA;
c.b = 0xD;
std::cout << std::hex << c.raw;
}