Have you noticed the awkward situation with enums in
C++? Built-in enum class is missing
basic features, such as string conversion. There are several approaches to
address this, but most seem to involve unnatural syntax or code
repetition. See some here.
Better Enums gives you rich, reflective enums with the nicest syntax yet seen.1 All you have to do is add one short and simple header file to your project, and you are ready to go.
#include <enum.h> ENUM(Channel, int, Red, Green, Blue);
This gives you an int-sized enum type with all sorts of
reflective capacity, including string conversions, value listing,
compile-time operations, static information about the range of declared
constants, and (last and probably least) the name "Channel"
itself. You can even assign explicit values to constants and alias them
like with a normal built-in enum.
The enum is easy to maintain. There is no duplication of value names, no repetition of cumbersome macros, and no generator to run on every build. The library is header-only and has no dependencies, so there aren't any object files to link with. It is also standard C++.
Better Enums is free, available under the BSD license. The author is committed to further development and support, so please contact me, open an issue on GitHub, or ask a question on Stack Overflow.
Installation
Download enum.h and copy it to your project. That's it! Just make sure it's in your include path and you are compiling with gcc or clang in C++11 mode.
msvc support is coming in a near-future version
with some enum features disabled. This is because
msvc's support for constexpr is
lagging. The same patch will probably make it possible to use Better Enums
with C++98.
Tutorial
Create a file and put this code in it:
#include <iostream>
#include <enum.h>
ENUM(Channel, int, Red, Green, Blue);
int main()
{
Channel my_channel = Channel::Green;
std::cout
<< "Channel "
<< my_channel.to_string()
<< " has value "
<< my_channel.to_integral()
<< std::endl;
return 0;
}
Compile and run, and you should see the output Channel Green has value 1. Congratulations! You have compiled your first Better Enum.
Values are assigned to Better Enums just like to regular C++ enums. That means you can change the enum above to something like this:
ENUM(Channel, int, Red, Green = 5, Blue, Last = Blue);
and the result would be just as you'd expect: Red is 0,
Green is 5, Blue is 6, and Last is
also 6.
There is no need for Last, however. Every Better Enum comes
with a built-in value called _last. So, if you have
ENUM(Channel, int, Red, Green, Blue);
Then Channel::_last is Channel::Blue! In fact,
Channel also gets _first, _min,
_max, _span, and _size. These
built-in values have underscores so that you can define your own enums
without having to worry about naming problems:
ENUM(Position, int, first, last, other);
You already saw how to convert an enum to a string or an integer. As you might guess, it is also possible to go the other way:
Channel my_channel = Channel::_from_string("Blue");
Channel my_channel = Channel::_from_integral(2);
If your code tries to convert an invalid string or integer to a
Channel, it will get an std::runtime_error
exception.
You can iterate over all the declared values of an enum:
for(Channel channel : Channel::_values)
std::cout << channel.to_string() << std::endl;
and directly over their names with Channel::_names.
Finally, all of the above can be done at compile time. This means you can do all sorts of parsing and processing at the same time the rest of your code is being compiled, improving runtime and startup performance! See some examples 2 3.
Where to go from here
- Download Better Enums and start using them in your project
- Browse the commented code samples, including advanced usage
- Read the API documentation
- View, discuss, and contribute on GitHub
- Contact the author directly — all feedback is welcome!