In daily C++ development, enumeration types are often used to represent a set of limited discrete values, such as status codes, configuration options, event types, and so on. The problem is that standard C++ has very limited support for enumerations, especially when we need to convert enumeration values to strings or parse enumeration values from strings, which often requires writing lengthy <span>switch</span> statements or maintaining a mapping table. This is both cumbersome and error-prone.
C++20 introduces some useful features (such as <span>constexpr</span>, <span>consteval</span>, improved template deduction, etc.), which provide the possibility to write more generic “reflection tools.” Although compile-time reflection at the standardization level is still in the proposal stage, the community has already made many excellent attempts, and today I want to share one of them, a lightweight library called Conjure-Enum.
The goal of this library is clear: to make the conversion between enumeration and type names to strings simple, with zero boilerplate code, and to complete everything at compile time.
📚 The C++ Knowledge Base has launched on ima! The current content covered by the knowledge base is shown in the image below👇👇👇

📌 Students interested in the knowledge base can add the assistant vx (cppmiao24) with the note 【Knowledge Base】 or click 👉 C++ Knowledge Base (tap to jump) to view the complete introduction to the knowledge base~
Common Pain Points Review
First, let’s look at a common requirement: we have a status enumeration and need to output a string in the logs.
enum class Status {
Idle,
Running,
Stopped,
Error
};
std::string to_string(Status s) {
switch (s) {
case Status::Idle: return "Idle";
case Status::Running: return "Running";
case Status::Stopped: return "Stopped";
case Status::Error: return "Error";
}
return "Unknown";
}
The drawbacks of this approach are obvious:
- Every time the enumeration is modified,
<span>to_string</span>must be updated accordingly; - Reverse parsing (string to enumeration) requires writing a mapping again;
- It is easy to miss branches or make mistakes.
As a result, many teams resort to macros, code generation, or third-party libraries to solve this. The idea behind Conjure-Enum is to parse the names of enumerations at compile time, avoiding the need to write repetitive logic.
The Core Idea of Conjure-Enum
The implementation of Conjure-Enum relies on the function signature strings provided by the compiler (such as <span>__PRETTY_FUNCTION__</span> or <span>__FUNCSIG__</span>), and then extracts the names of enumeration constants at compile time. With C++20’s <span>consteval</span>/<span>constexpr</span> capabilities, all of this is completed at compile time without runtime overhead.
The usage is very simple: just register the enumeration with a macro, and you will automatically obtain a series of helper functions.
Basic Usage Example
Define an enumeration and enable reflection:
#include <conjure/enum.hpp>
enum class Status {
Idle,
Running,
Stopped,
Error
};
// Register enumeration
CONJURE_ENUM(Status);
Now we can directly call the generated utility functions:
#include <iostream>
int main() {
Status s = Status::Running;
// Enumeration to string
std::cout << conjure::enum_name(s) << "\n"; // Output: Running
// String to enumeration
auto parsed = conjure::enum_cast<Status>("Stopped");
if (parsed) {
std::cout << "Parsed OK\n";
}
// Iterate over all enumeration values
for (auto v : conjure::enum_values<Status>()) {
std::cout << conjure::enum_name(v) << " ";
}
}
As you can see, we no longer need to maintain an additional mapping table, the logic becomes very concise, and all strings come from compile-time parsing, ensuring consistency with the enumeration definition.
Type Name Reflection
In addition to enumerations, Conjure-Enum also provides the ability to obtain type names, which is useful for logging, debugging, or serialization.
#include <iostream>
#include <vector>
int main() {
std::cout << conjure::type_name<int>() << "\n"; // int
std::cout << conjure::type_name<std::vector<std::string>>() << "\n";
// std::vector<std::string, std::allocator<std::string>>
}
This method avoids hardcoding type name strings, which is especially convenient during template debugging.
Comparison with Other Solutions
Many people might think of another common library, magic_enum. The two have some overlapping functionalities, but there are still some differences:
- magic_enum: More comprehensive functionality, supports range queries, value mapping, bitmasking, and other advanced features, but the implementation is more complex.
- Conjure-Enum: A lighter implementation, smaller codebase, fewer dependencies, suitable for scenarios with less complex functional requirements.
If the project only needs “enumeration ↔ string” and type name retrieval, Conjure-Enum is simple enough; if more rich operations are needed, consider magic_enum.
Applicable Scenarios
- Logging and Debugging: Avoid hardcoding when printing enumeration values and type names.
- Configuration Parsing: Directly map strings from configuration files to enumerations.
- Serialization/Deserialization: Enumerations are often stored as strings in JSON/YAML, which is exactly applicable.
- Code Maintainability: When adding new enumeration constants, there is no need to worry about missing mapping logic.
Notes
- Due to reliance on compiler-built function signatures, the output format may vary slightly between different compilers. Conjure-Enum has already made adaptations, but if you encounter a relatively new compiler version, it may need verification.
- Compared to standardized reflection, this is still a “trick”; once C++ provides a formal compile-time reflection mechanism in the future, such libraries may gradually be replaced.
- In some extreme scenarios (such as when there are many enumeration definitions and string processing is very complex), it may slightly increase compile time, but the runtime overhead is almost zero.
Conjure-Enum provides a very lightweight way to solve the common “enumeration ↔ string” and “type name retrieval” problems in C++ development. Its characteristics are:
- Simple interface, almost zero boilerplate code;
- Completely done at compile time, introducing no runtime burden;
- Small codebase, easy to integrate into projects.
If you are writing a C++20 project and do not want to maintain a lot of repetitive code for enumerations and type names, you might want to give this library a try.
Recommended Reading:
C++ Direct Train to Major Companies (For students interested in the training camp, you can read this article to learn about the details of the training camp, or add the assistant vx: cppmiao24 to quickly learn about the training camp related introduction)
I recommend a super useful C++ testing library: CMocka
I recommend a compile-time regular expression library for C++: CTRE