Introducing TRLC Enum: A Modern C++ Enum Library for Enhanced Usability

Tráng Lê Công - Oct 31 - - Dev Community

🚀 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>
Enter fullscreen mode Exit fullscreen mode
TRLC_ENUM(Rainbow,
          RED,
          ORANCE,
          YELLOW,
          GREEN,
          BLUE,
          INDIGO,
          VIOLET)
Enter fullscreen mode Exit fullscreen mode
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."))
Enter fullscreen mode Exit fullscreen mode
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)
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

Each enum and element contains a tag() for its name and a dump() 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;
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Check the repository for detailed.

Thanks for checking out trlc_enum! Happy coding, and I hope this library helps simplify your C++ projects.


.