Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access fields in a named union

Tags:

c++

c++11

unions

I want to have a named union in the following struct so that I can memcpy it without knowing what field is "active".

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} {}
};

How can I initialize the fields in the constructors? Neither v.li{li} nor li{li} are working.

I also tried v{li} but it work only for the first constructor because it cast the 3 others to int.


EDIT: From @StoryTeller answer and comment:

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 };
  };
};
like image 329
dblouis Avatar asked Oct 31 '17 09:10

dblouis


1 Answers

You can only initialize direct members of Literal in its c'tors member initializer list. Aggregate initialization of the union member won't work due to narrowing conversions. So your options are to:

  1. Name the union member type, and add appropriate c'tors to it.
  2. Recurse in order to force the union fields into being treated as fields of the Literal class. Have a union of unions, and rely on the common initial sequence guarantee:

    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} {}
    

    The above allows you to refer to each field by name, on account of the anonnymous union member, as well as lumping them together using the named v member. But I'll be the first to admit, it's ugly.

like image 69
StoryTeller - Unslander Monica Avatar answered Sep 28 '22 14:09

StoryTeller - Unslander Monica