🚀 Overview
I’m thrilled to introduce trlc_enum
, an open-source C++ library designed to push enums beyond their traditional limitations. By enhancing enums with attributes and supporting compile-time operations, trlc_enum
is here to make C++ enums more powerful, traceable, and easy to use.
🔑 Features
Declaration
With trlc_enum
, enums are declared with attributes such as value, desc, and tag. This design allows us to add detailed metadata to enums, enhancing both code readability and usability.
#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.
Attributes
Enum elements come with attributes like name, value, and desc that can be accessed at compile-time, making it easy to perform checks or validations as you code.
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;
Conversion
Easily convert enums from values or strings with the fromValue
and fromString
methods.
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 type is
constexpr std::optional<enumtype>
, making error handling straightforward..
Iterators
Enumerate over enums at both compile- and runtime using iterators.
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;
Traceability
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;
Each enum and element contains a
tag()
for its name and adump()
method for JSON representation of its properties, useful for debugging and data inspection.
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;
}
Customization
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)
Check the repository for detailed.
Thanks for checking out trlc_enum
! Happy coding, and I hope this library helps simplify your C++ projects.
Top comments (2)
Hello
I've tried a few minutes the library. I have seen interesting stuffs.
However, I believe your repository is missing at least 2 things:
Using your
example.cpp
:This is quite relevant I think.
Have you disable the copy constructor/operator of the enum type? Considered their size and supposing they are constexpr obejcts, it might be relevant.
@pgradot Thank you for reading and providing feedback on it.
I will add some more usage examples when I use this enum for my upcoming project.
The size of enumtype is essentially the size of a struct that includes value_type, std::string_view name, and tag. With the default trlc_enum, I'm using value_type: int64_t, so the total size will be: int64_t + std::string_view + std::string_view = 8 + 16 + 16 = 40
However, enums are
constexpr
, so they will be evaluated and replaced at compile time. This will reduce execution costs at runtime.I didn’t disable the copy constructor/operator of the enum type because I want to be able to use it flexibly