a few lines of macros for making a printable enum.
Last active
July 18, 2025 22:16
-
-
Save riogu/1d3ad87b662916c39e7a6ae44e56d054 to your computer and use it in GitHub Desktop.
printable C++ enums with macros
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "printable-enum.hpp" | |
| make_enum(my_enum, foo, bar, what, something); | |
| make_enum(another_enum, foo, bar, gaming, something); | |
| #include <print> | |
| int main() { | |
| my_enum somevar = my_enum::bar; | |
| std::print("my enum was: {}\n", somevar.to_str()); | |
| another_enum var = another_enum::gaming; | |
| std::print("my enum was: {}\n", var.to_str()); | |
| switch (somevar) { | |
| case my_enum::foo: | |
| case my_enum::what: | |
| default: | |
| break; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #define EVAL0(...) __VA_ARGS__ | |
| #define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__))) | |
| #define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) | |
| #define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) | |
| #define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) | |
| #define EVAL5(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) | |
| #ifdef _MSC_VER | |
| // MSVC needs more evaluations | |
| #define EVAL6(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__))) | |
| #define EVAL(...) EVAL6(EVAL6(__VA_ARGS__)) | |
| #else | |
| #define EVAL(...) EVAL5(__VA_ARGS__) | |
| #endif | |
| #define EMPTY() | |
| #define DEFER(id) id EMPTY() | |
| #define MAP_END(...) | |
| #define MAP_OUT | |
| #define MAP_GET_END2() 0, MAP_END | |
| #define MAP_GET_END1(...) MAP_GET_END2 | |
| #define MAP_GET_END(...) MAP_GET_END1 | |
| #define MAP_NEXT0(test, next, ...) next MAP_OUT | |
| #define MAP_NEXT1(test, next) DEFER ( MAP_NEXT0 ) ( test, next, 0) | |
| #define MAP_NEXT(test, next) MAP_NEXT1(MAP_GET_END test, next) | |
| #define MAP_INC(X) MAP_INC_ ## X | |
| #define MAP0(f, x, peek, ...) f(x) DEFER ( MAP_NEXT(peek, MAP1) ) ( f, peek, __VA_ARGS__ ) | |
| #define MAP1(f, x, peek, ...) f(x) DEFER ( MAP_NEXT(peek, MAP0) ) ( f, peek, __VA_ARGS__ ) | |
| #define map_macro(f, ...) EVAL(MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) | |
| #include <string> | |
| #define enum_str_repr(_v) case _v: return #_v; | |
| #define make_enum(name, ...) \ | |
| struct name { \ | |
| enum impl { __VA_ARGS__ } value; \ | |
| \ | |
| [[nodiscard]] constexpr std::string to_str() { \ | |
| switch(value) { \ | |
| map_macro(enum_str_repr, __VA_ARGS__) \ | |
| default: return "unknown enum."; \ | |
| } \ | |
| } \ | |
| \ | |
| constexpr operator impl(){ return value; } \ | |
| name(impl some): value(some){} \ | |
| name() {} \ | |
| }; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment