访问命名联合中的字段

Access fields in a named union

本文关键字:字段 访问      更新时间:2023-10-16

我想在下面的结构中有一个命名的联合,这样我就可以memcpy它,而不知道哪个字段是"活动"的。

struct Literal {
  enum class Type : size_t {
    INT = 1,
    LONG,
    FLOAT,
    DOUBLE
  } type;
  union {
    int li;
    long ll;
    float lf;
    double ld;
  } v;
  constexpr Literal(int li): type{Type::INT}, v.li{li} {}
  constexpr Literal(long ll): type{Type::LONG}, v.ll{ll} {}
  constexpr Literal(float lf): type{Type::FLOAT}, v.lf{lf} {}
  constexpr Literal(double ld): type{Type::DOUBLE}, v.ld{ld} {}
};

如何初始化构造函数中的字段?v.li{li}li{li}都不起作用。

我也尝试了v{li}但它仅适用于第一个构造函数,因为它将其他 3 个构造函数转换为 int。


编辑:从@StoryTeller答案和评论:

struct Literal {
  enum class Type : size_t {
    INT = 1,
    LONG,
    FLOAT,
    DOUBLE
  } type;
  union {
    #define UNION_FIELDS int li; long ll; float lf; double ld;
    union { UNION_FIELDS } value;
    union { UNION_FIELDS };
  };
};

只能在其 c'tors 成员初始值设定项列表中初始化Literal的直接成员。由于缩小转换范围,工会成员的聚合初始化将不起作用。因此,您的选择是:

  1. 命名工会成员类型,并向其添加适当的 c'tor。
  2. 递归以强制将联合字段视为Literal类的字段。有一个联合的联合,并依赖于共同的初始序列保证:

    union {
      union {
          int li;
          long ll;
          float lf;
          double ld;
      } v;
      union {
          int li;
          long ll;
          float lf;
          double ld;
      };
    };
    constexpr Literal(int li): type{Type::INT}, li{li} {}
    constexpr Literal(long ll): type{Type::LONG}, ll{ll} {}
    constexpr Literal(float lf): type{Type::FLOAT}, lf{lf} {}
    constexpr Literal(double ld): type{Type::DOUBLE}, ld{ld} {}
    

    以上允许您根据非匿名工会成员的名称引用每个字段,以及使用命名的v成员将它们集中在一起。但我会第一个承认,这很丑。