A union is a struct
in which all members are allocated at the same
address so that the union
occupies as much space as its largest
member, e.g.
// This is a naked union because it doesn't have an associated indicator
// for which member it holds.
union Value {
Node* p;
int i;
}
// The language doesn't keep track of which kind of value is held by a
// union, so the programmer must do that themselves, e.g.
enum Type { ptr, num };
struct Entry {
string name;
Type t;
Value v; // use v.p if t == ptr; use v.i if t == num
};
// Sample usage.
void f(Entry* pe) {
if (pe->t == num)
std::cout << pe->v.i;
// ...
}
Maintaining the correspondence between Entry
’s t
and the type held
in the union is error-prone. One approach is to encapsulate the union
and type-field in a class, and only offer access through member
functions that use the union correctly.
The STL type, variant
, can be used to eliminate most direct uses of
unions, e.g.
struct Entry {
string name;
std::variant<Node*, int> v;
}
void f(Entry* pe) {
if (std::holds_alternative<int>(pe->v))
std::cout << std::get<int>(pe->v);
// ...
}
- A Tour of C++ (Second Edition). Chapter 2. User-Defined Types. Bjarne Stroustrup. 2018. ISBN: 978-0-13-499783-4 .
notes, “For many uses, a
variant
is simpler and safer to use than aunion
.” When would we ever prefer aunion
to avariant
?