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 };
};
};
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With