Unfortunately, unions are so restricted in C++ that they are all but useless. The Key union type that I've written for Kaleidoglyph isn't compliant with the standard, and only works because of a gcc extension. This does allow (in my opinion much greater code clarity, but it is technically undefined behaviour if any member of a union is read after a different member of that union is written. Therefore, the goal is now to replace that Key union (and any other unions) with a class or set of classes that are not crippled by the failure of the standard to provide reasonable guarantees of behaviour.
Requirements
The Key type and its variants must meet all of the following criteria:
Instances must be no more than two bytes
There must be a way to examine a Key object and determine which variant that object belongs to, or at least a way to test if a Key object is a given variant
It must be possible to store an array of Key objects
It must not be endian-sensitive
Option 1
The Key type becomes a base class with only one data member: a two-byte integer (uint16_t).
Variant types such as KeyboardKey are derived from the base class Key, and do explicit bit-twiddling to access the different bit field members.
Option 2
The Key type is a class with one two-byte data member.
Variant types (e.g. KeyboardKey) are not inherited, and store their data in bit fields that handle the bit-twiddling for us. We use type-conversion functions to convert from Key to the variants.
Option 3
Like option 2, but the variant types are defined inside the Key class in the public section, so they're named Key::Keyboard instead of KeyboardKey. This would be nice and clear for the built-in types, but not as good for the plugin types (e.g. Key::Qukeys won't be possible, but QukeysKey will).
The problem
Unfortunately, unions are so restricted in C++ that they are all but useless. The
Key
union type that I've written for Kaleidoglyph isn't compliant with the standard, and only works because of a gcc extension. This does allow (in my opinion much greater code clarity, but it is technically undefined behaviour if any member of a union is read after a different member of that union is written. Therefore, the goal is now to replace thatKey
union (and any other unions) with a class or set of classes that are not crippled by the failure of the standard to provide reasonable guarantees of behaviour.Requirements
The
Key
type and its variants must meet all of the following criteria:Key
object and determine which variant that object belongs to, or at least a way to test if aKey
object is a given variantKey
objectsOption 1
The
Key
type becomes a base class with only one data member: a two-byte integer (uint16_t
).Variant types such as
KeyboardKey
are derived from the base classKey
, and do explicit bit-twiddling to access the different bit field members.Option 2
The
Key
type is a class with one two-byte data member.Variant types (e.g.
KeyboardKey
) are not inherited, and store their data in bit fields that handle the bit-twiddling for us. We use type-conversion functions to convert fromKey
to the variants.Option 3
Like option 2, but the variant types are defined inside the
Key
class in the public section, so they're namedKey::Keyboard
instead ofKeyboardKey
. This would be nice and clear for the built-in types, but not as good for the plugin types (e.g.Key::Qukeys
won't be possible, butQukeysKey
will).