Access fields in a named union - c++

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:
Name the union member type, and add appropriate c'tors to it.
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.

Related

Class that contains a list of itself

This is what I am trying to do (in my header file):
#include <forward_list>
class Data {
public:
Data(int type, union data value);
int which_type();
void set_int(const int& i);
void set_list(std::forward_list<Data*>& l);
int get_int();
std::forward_list<Data*>* get_list();
private:
union data actual_data;
int type;
};
union data {
int i;
std::forward_list<Data*> l;
};
If everything were to work properly, this would create a class which could contain an integer or a list, and it would be as type-safe as possible because I would call the which_type function before every call to one of the get functions, and the get functions would throw an exception if the object isn't the correct type.
However, this isn't possible because Data needs a union data, and union data needs a forward_list<Data*>. I believe boost has what I am looking for, but is there a way to do this without boost? I would just rather use the standard library in order to learn more about the c++ standard library.
All you need is to forward declare the class Data and then declare the union data before the class Data proper declaration.
#include <forward_list>
class Data;
union data {
int i;
std::forward_list<Data*> l;
};
class Data {
public:
Data(int type, union data value);
int which_type();
void set_int(const int& i);
void set_list(std::forward_list<Data*>& l);
int get_int();
std::forward_list<Data*>* get_list();
private:
union data actual_data;
int type;
};
Compiles with g++ and clang++ with no problem.
Class members may not be incomplete class types (although they may be pointers or references to such types). So you need to define union data before you can declare a member of this type in Data. This is straightforward:
class Data {
public:
Data(int type, union data value);
int which_type();
void set_int(const int& i);
void set_list(std::forward_list<Data*>& l);
int get_int();
std::forward_list<Data*>* get_list();
private:
union data {
int i;
std::forward_list<Data*> l;
} actual_data;
int type;
};
Another solution is to define the union first, since it doesn't need the Data class to be complete, since it only uses a pointer to it.
union data {
int i;
std::forward_list<class Data*> l;
};
class Data {
public:
Data(int type, union data value);
int which_type();
void set_int(const int& i);
void set_list(std::forward_list<Data*>& l);
int get_int();
std::forward_list<Data*>* get_list();
private:
data actual_data;
int type;
};

Member variable aliasing in a simple struct using union

I have a simple point struct that I would like to inherit:
struct PointXYZ
{
double x, y, z;
};
class extendedPoint : public PointXYZ
{
public:
double getXYZ(int i);
void setXYZ(int i, double value);
private:
int moreproperties;
};
The get-set function is indexed because I'd like to be able to loop through getting and setting the xyz values. I'd like to link the concept of indexed xyz and standalone x,y,z by modifying my base class as described in the answer to this post:
struct PointXYZ
{
union {
struct {
double x, y, z;
};
double xyz[3];
};
};
class extendedPoint : public PointXYZ
{
public:
double getXYZ(int i) { return xyz[i]; }
void setXYZ(int i, double value) { xyz[i] = value; }
private:
int moreproperties;
};
But this post directly contradicts the first post on whether the following is valid:
double dostuff()
{
PointXYZ p;
p.x = 123.88;
return p.xyz[0];
}
So, is PointXYZ's use of union valid c++ and consistent between compilers or not?
From the standard:
In a union, at most one of the non-static data members can be active at any time, that is, the value of at
most one of the non-static data members can be stored in a union at any time. [ Note: One special guarantee
is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout
structs that share a common initial sequence (9.2), and if an object of this standard-layout union type
contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of
standard-layout struct members; see 9.2. — end note ]
Seems to me that the special guarantee indicates that
struct PointXYZ {
union {
struct {
double xyz[3];
};
struct {
double x, y, z;
};
};
};
should work just fine when reading the member that was not last written (See it happen).
Note, however, that according to the specs, your example of
struct PointXYZ {
union {
struct {
double xyz[3];
};
double x, y, z;
};
};
is undefined behaviour when reading the member that was not last written (See it happen). When setting xyz[0], xyz[1] and xyz[2], all of x, y and z have the same value as xyz[0] in the linked example. I would expect most compilers to behave like this, but the standard does not guarantee it.
struct PointXYZ {
union {
double xyz[3];
struct {
double x, y, z;
};
};
};
Depending on the compiler / platform, you may have data alignment issues (it's possible though unlikely).
x, y, z may not reside in memory in correspondence with xyz[0], xyz[1], xyz[2].
C++ guarantees that elements of the xyz array are laid out contiguously, but it only guarantees that the address of an element of the struct is greater than the address of all earlier-declared elements (of course many compilers offer #pragma to control packing and alignment).
About the type punning matter (the practice of reading from a different union member than the one most recently written to)...
you could say that this isn't type punning (types match, so there is no pun, it's merely aliasing), but still, from an the viewpoint of the language standard, the member written to and read from are different, which is undefined in C++.
Anyway, generally, you'll have the expected result...
With GCC it's even guaranteed to work (even with -fstrict-aliasing):
Type punning
A member of a union object is accessed using a member of a different type
As a side note consider that anonymous unions are permitted but C++ prohibits anonymous structs (a lot of compilers allow them).
What about the following solution?
class PointXYZ
{
public:
double getXYZ(unsigned i) { return xyz[i]; }
void setXYZ(unsigned i, double value) { xyz[i] = value; }
double &x() { return xyz[0]; }
double &y() { return xyz[1]; }
double &z() { return xyz[2]; }
private:
double xyz[3];
};

Initializing default values in a struct

If I needed to initialize only a few select values of a C++ struct, would this be correct:
struct foo {
foo() : a(true), b(true) {}
bool a;
bool b;
bool c;
} bar;
Am I correct to assume I would end up with one struct item called bar with elements bar.a = true, bar.b = true and an undefined bar.c?
You don't even need to define a constructor
struct foo {
bool a = true;
bool b = true;
bool c;
} bar;
To clarify: these are called brace-or-equal-initializers (because you may also use brace initialization instead of equal sign). This is not only for aggregates: you can use this in normal class definitions. This was added in C++11.
Yes. bar.a and bar.b are set to true, but bar.c is undefined. However, certain compilers will set it to false.
See a live example here: struct demo
According to C++ standard Section 8.5.12:
if no initialization is performed, an
object with automatic or dynamic storage duration has indeterminate value
For primitive built-in data types (bool, char, wchar_t, short, int, long, float, double, long double), only global variables (all static storage variables) get default value of zero if they are not explicitly initialized.
If you don't really want undefined bar.c to start with, you should also initialize it like you did for bar.a and bar.b.
You can do it by using a constructor, like this:
struct Date
{
int day;
int month;
int year;
Date()
{
day=0;
month=0;
year=0;
}
};
or like this:
struct Date
{
int day;
int month;
int year;
Date():day(0),
month(0),
year(0){}
};
In your case bar.c is undefined,and its value depends on the compiler (while a and b were set to true).
An explicit default initialization can help:
struct foo {
bool a {};
bool b {};
bool c {};
} bar;
Behavior bool a {} is same as bool b = bool(); and return false.

How to pass a union as a function parameter without defining it first?

Is it possible define a union temporary inside the function call, rather than defining it previously and then passing it in the parameters?
Example:
union data_t{
double delaySeconds;
float scale;
float rotation;
};
void someFunction(data_t){}
Now I want to call someFunction, using whatever element of the union is appropriate:
someFunction(WHAT DO I PUT HERE);
For example, if you are passing to a function that expects a type that includes a constructor, you can define your temporary right there in the function call. But I've tried a variety of ways with this union with no luck. For example, suppose I want to pass a float assigned to scale:
someFunction(data_t.scale(2.0));
You can define a constructor for your union for initializing the members. But, you need a mechanism to distinguish which field was set. Below, I define a helper enum, and extend your data_t to allow for inheritance and member distinction.
enum data_t_type { DelaySeconds, Scale, Rotation };
struct data_t {
union {
double delaySeconds;
float scale;
float rotation;
};
union {
unsigned char flags;
struct {
unsigned char isDelaySeconds : 1;
unsigned char isScale : 1;
unsigned char isRotation : 1;
};
};
data_t () : flags(0) {}
};
Now, the initialization is actually done with a template that takes the data_t_type as a parameter.
template <data_t_type> struct data_type {};
template <> struct data_type<DelaySeconds> : data_t {
data_type (double x) { delaySeconds = x; isDelaySeconds = 1; }
};
template <> struct data_type<Scale> : data_t {
data_type (float x) { scale = x; isScale = 1; }
};
template <> struct data_type<Rotation> : data_t {
data_type (float x) { rotation = x; isRotation = 1; }
};
So now, you can call your function like so:
someFunction(data_type<Scale>(2.0));
Since a data_type<> is a data_t, someFunction() gets the right type.

Initializing aggregate unions

I've got a union :
union my_union
{ short int Int16; float Float; };
I'd like to create :
const my_union u1 = ???;
const my_union u2 = ???;
and initialize their values to be of different types respectively :
u1 -> int16
u2 -> float
How do I do that ? If the above is not possible, are there any workarounds?
union can have any number of constructors - this will work for any datatypes without constructor, so your example is well if exclude string (or make pointer to string)
#include <string>
using namespace std;
union my_union
{
my_union(short i16):
Int16(i16){}
my_union(float f):
Float(f){}
my_union(const string *s):
str(s){}
short int Int16; float Float; const string *str;
};
int main()
{
const my_union u1 = (short)5;
const my_union u2 = (float)7.;
static const string refstr= "asdf";
const my_union u3 = &refstr;
}
There is more complicated way to create class, that owns by union, class must have a selector (scalar or vector datatype used) - to correctly destroy string.
Notwithstanding the ban on non-POD member data (as elaborated above) the Standard says:
at 8.5.1.15: When a union is initialized with a brace-enclosed
initializer, the braces shall only contain an initializer for
the first member of the union.
so
const my_union u1 = {1};
should work but this form cannot be used for the second (and subsequent) members.
Unions cannot contain non-POD data types such as string, so your question is meaningless.