A powerful C++ enum library that enhances traditional enums by allowing the use of attributes and providing support for compile-time operations.
We can declare enums in a traditional way, with fields or mix.
#include <trlc/enum.hpp>
TRLC_ENUM(Rainbow,
RED,
ORANCE,
YELLOW,
GREEN,
BLUE,
INDIGO,
VIOLET)
TRLC_ENUM(Cars,
SEDAN = TRLC_FIELD(value = 1, desc = "A comfortable car for daily commuting and family trips."),
SUV = TRLC_FIELD(value = 2, desc = "A versatile vehicle built for various terrains and passenger capacity."),
TRUCK = TRLC_FIELD(value = 3, desc = "A powerful vehicle designed for transporting heavy loads and equipment."),
JEEP = TRLC_FIELD(value = 4, desc = "A rugged vehicle ideal for off-road adventures and exploration."))
TRLC_ENUM(Validate,
NON_FIELD,
WITH_DEFAULT = TRLC_FIELD(value = 5),
WITH_DESC = TRLC_FIELD(desc = "With description."),
FULL_FIELD = TRLC_FIELD(value = 100, desc = "Full feild."),
NEGATIVE_VALUE = TRLC_FIELD(value = -100, desc = "Default trlc enum can support negative value."),
END)
This Enum is essentially a struct, so we can declare it within the scope where the struct can be declared.
We can use the attributes name
, value
, desc
and tag
of trlc enum
static_assert(Rainbow::ORANCE.tag() == "Rainbow");
static_assert(Rainbow::RED.value() == 0);
static_assert(Rainbow::GREEN.name() == "GREEN");
static_assert(Cars::JEEP.value() == 4);
static_assert(Cars::SUV.name() == "SUV");
static_assert(Cars::SEDAN.desc() == "A comfortable car for daily commuting and family trips.");
static_assert(Validate::NEGATIVE_VALUE.name() == "NEGATIVE_VALUE");
static_assert(Validate::NEGATIVE_VALUE.value() == -100);
static_assert(Validate::NEGATIVE_VALUE.desc() == "Default trlc enum can support negative value.");
std::cout << "Compile time attributes check passed." << std::endl;
We can use the fromValue and fromString functions to look up enum elements.
constexpr auto rainbow_green_optional{Rainbow::fromValue(3)};
static_assert(rainbow_green_optional.has_value() == true);
static_assert(rainbow_green_optional.value() == Rainbow::GREEN);
constexpr auto cars_suv_optional{Cars::fromString("SUV")};
static_assert(cars_suv_optional.has_value() == true);
static_assert(cars_suv_optional.value() == Cars::SUV);
std::cout << "Compile time fromValue(), fromString() check passed." << std::endl;
The return value will be constexpr
std::optional<enumtype>
.
We can also use iterators for enum classes. And it also supports compile-time!
constexpr auto check_size_of_rainbow = [&]() -> size_t
{
auto size{0};
for (auto elem : Rainbow::iterator)
{
size++;
}
return size;
};
static_assert(check_size_of_rainbow() == Rainbow::size());
std::cout << "Compile time iterators check passed." << std::endl;
From an enum element, we can also retrieve its holder.
constexpr auto suv{cars_suv_optional.value()};
static_assert(suv.tag() == "Cars");
static_assert(suv.holder().tag() == "Cars");
static_assert(suv.holder().TRUCK == Cars::TRUCK);
std::cout << "Compile time holder check passed." << std::endl;
The tag property of the enum or enum element is the name of that enum.
Each enum or enum element has a dump() function that operates at runtime.
std::cout << "[1] Enum Rainbow :";
std::cout << Rainbow::dump() << std::endl;
std::cout << "[2] Enum Cars :";
std::cout << Cars::dump() << std::endl;
std::cout << "[3] Enum Validate :\n";
// Of course, we can also use iterators to print the properties.
for (auto elem : Validate::iterator)
{
std::cout << elem.dump() << std::endl;
}
It returns a JSON string of the properties associated with the enum element and a list of elements for the enum.
We can use Enum::enum_type
just like a regular type.
Cars::enum_type a_car{Cars::SUV};
auto functor = [](const Cars::enum_type& car) -> void
{
switch (car)
{
case Cars::SEDAN:
std::cout << "SEDAN :" << car.dump() << std::endl;
break;
case Cars::SUV:
std::cout << "SUV :" << car.dump() << std::endl;
break;
case Cars::TRUCK:
std::cout << "TRUCK :" << car.dump() << std::endl;
break;
case Cars::JEEP:
std::cout << "JEEP :" << car.dump() << std::endl;
break;
}
};
functor(a_car);
a_car = Cars::TRUCK;
functor(a_car);
Currently, TRLC_ENUM
uses trlc:DefaultEnumDef<>
, but you can also define an enum definition and use it with TRLC_ENUM_DETAIL
.
template<class Holder>
struct CustomEnumDefine
{
using holder = Holder;
using value_type = uint32_t;
using value_search_policy = trlc::policy::BinarySearchPolicy;
using name_search_policy = trlc::policy::CaseInsensitiveStringSearchPolicy;
using unknown_policy = trlc::policy::UnknownPolicy;
using enum_type = trlc::Enum<value_type, holder>;
using iterator = trlc::EnumIterator<holder>;
};
TRLC_ENUM_DETAIL(Colors, CustomEnumDefine,
RED,
BLUE,
GREEN)
The output of running all the blocks above will be as follows:
Compile time attributes check passed.
Compile time fromValue(), fromString() check passed.
Compile time iterators check passed.
Compile time holder check passed.
[1] Enum Rainbow :[
{"tag": "Rainbow, "value": 0, "name": "RED", "desc": ""},
{"tag": "Rainbow, "value": 1, "name": "ORANCE", "desc": ""},
{"tag": "Rainbow, "value": 2, "name": "YELLOW", "desc": ""},
{"tag": "Rainbow, "value": 3, "name": "GREEN", "desc": ""},
{"tag": "Rainbow, "value": 4, "name": "BLUE", "desc": ""},
{"tag": "Rainbow, "value": 5, "name": "INDIGO", "desc": ""},
{"tag": "Rainbow, "value": 6, "name": "VIOLET", "desc": ""},
]
[2] Enum Cars :[
{"tag": "Cars, "value": 1, "name": "SEDAN", "desc": "A comfortable car for daily commuting and family trips."},
{"tag": "Cars, "value": 2, "name": "SUV", "desc": "A versatile vehicle built for various terrains and passenger capacity."},
{"tag": "Cars, "value": 3, "name": "TRUCK", "desc": "A powerful vehicle designed for transporting heavy loads and equipment."},
{"tag": "Cars, "value": 4, "name": "JEEP", "desc": "A rugged vehicle ideal for off-road adventures and exploration."},
]
[3] Enum Validate :
{"tag": "Validate, "value": -100, "name": "NEGATIVE_VALUE", "desc": "Default trlc enum can support negative value."}
{"tag": "Validate, "value": 0, "name": "NON_FIELD", "desc": ""}
{"tag": "Validate, "value": 1, "name": "WITH_DESC", "desc": "With description."}
{"tag": "Validate, "value": 2, "name": "END", "desc": ""}
{"tag": "Validate, "value": 5, "name": "WITH_DEFAULT", "desc": ""}
{"tag": "Validate, "value": 100, "name": "FULL_FIELD", "desc": "Full feild."}
SUV :{"tag": "Cars, "value": 2, "name": "SUV", "desc": "A versatile vehicle built for various terrains and passenger capacity."}
TRUCK :{"tag": "Cars, "value": 3, "name": "TRUCK", "desc": "A powerful vehicle designed for transporting heavy loads and equipment."}
You can see the full example at [example]
To use this library, you need:
- CMake 3.10 or higher
- GCC, Clang or MSVC compiler with C++17 support
- GoogleTest (automatically fetched by CMake for testing)
This library can be used as CMake subdirectory.
- Fetch it, e.g. using [git submodules]:
git submodule add https://github.com/tranglecong/trlc_enum
git submodule update --init --recursive
Or you can use git clone: git clone https://github.com/tranglecong/trlc_enum.git
-
Call
add_subdirectory(path_to/trlc_enum)
or whatever your local path is to make it available in [CMake] file. -
Simply call
target_link_libraries(your_target PUBLIC trlc::enum)
to link this library and setups the include search path and compilation options.
You can also install trlc_enum library
-
Run CMake configure inside the library sources. If you want to build the UT and example set
-DTRLC_BUILD_TESTS=ON
,-DTRLC_BUILD_EXAMPLES=ON
cmake -DCMAKE_BUILD_TYPE=Debug -DTRLC_BUILD_TESTS=OFF -DTRLC_BUILD_EXAMPLES=OFF -DTRLC_GENERATE_RECURSIVE_MACRO=ON -S . -B ./build
The Enum library uses a recursive macro. The header macros will be generated when running the CMake configure through the execute Python script [macro_expansion_generator.py]. The default value of
TRLC_MACRO_RECURSIVE_MAX_NUM
is 64. If you want to change it, you can modify the CMake file or set-DTRLC_MACRO_RECURSIVE_MAX_NUM=xxx
. With xxx being the number you desire.
-
Build and install the library under
${CMAKE_INSTALL_PREFIX}
. You may be required to have sudo privileges to install in the/usr/*
.cmake --build ./build -j8 -- install
[Optional] if you want to run UT.
ctest --test-dir ./build
-
To use an installed library.
find_package(trlc REQUIRED) target_link_libraries(your_target PUBLIC trlc::enum)
Welcome contributions from everyone! If you’d like to help improve this project. Thank you for considering contributing to this project!