Welcome to the Better Enums tutorials! The code in this tutorial forms a valid program, which you can download and play with. The program runs as part of the automated test suite.
Representation
Let's go over some of the low-level properties of a Better Enum. This time, we will declare a more unusual enum than the ones we have seen.
#include <cassert> #include <iostream> #include <enum.h> BETTER_ENUM(ContentType, short, CompressedVideo = 5, PCM = 8, Subtitles = 17, Comment = 44)
This is for a hypothetical multimedia container file format. Perhaps the files have sections, and each one has a header:
struct Header { ContentType type; short flags; int offset; };
Here is what we have.
int main() { assert(sizeof(ContentType) == 2);
ContentType
behaves just like a short
1, in fact it simply wraps one. This
makes it possible to lay out structures in a predictable fashion:
Header header = {ContentType::PCM, 0, 0}; assert(sizeof(header) == 8); assert((size_t)&header.flags - (size_t)&header.type == 2);
uint16_t
is called ContentType
's underlying or representation type. If
you want to know the representation type of any enum you have declared, it is
available as the member type ::_integral
:
ContentType::_integral untrusted_value = 44;
Use this if you want a sized field to receive untrusted data, but aren't willing
to call it ContentType
yet because you have not validated it. Your validator
will likely call ::_from_integral_nothrow
, perform any other validation your
application requires, and then return ContentType
.
ContentType type = ContentType::_from_integral(untrusted_value); std::cout << type._to_string() << std::endl;
You have probably noticed the initializers on each of the constants in
ContentType
. This allows you to declare sparse enums for compatibility with
external protocols or previous versions of your software. The initializers don't
need to be literal integers — they can be anything that the compiler would
accept in a normal enum
declaration. If there was a macro called
BIG_FAT_MACRO
declared above, we could have written
Subtitles = BIG_FAT_MACRO
. We could also have written
Subtitles = CompressedVideo
.
The in-memory representation of an enum value is simply the number it has been
assigned by the compiler. You should be safe passing enums to functions like
fread
and fwrite
, and casting memory blocks known to be safe to struct
types containg enums. The enums will behave as expected.
return 0; }
It should properly be a
uint16_t
, and the rest of the header fields should also be explicitly sized. However, this code is trying to be compatible with C++98, where those names aren't available in a portable manner.↩