匿名联合在现实世界C ++编程中的实际应用

时间:2017-07-26 13:56:43

标签: c++ unions

我知道我们可以访问匿名联合而不创建它的对象(没有点), 但有人可以解释一下,匿名工会在现实世界的c ++编程中有什么用?

3 个答案:

答案 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; pp.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;
}