File: enum-reflection.md

package info (click to toggle)
glaze 7.0.2-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,036 kB
  • sloc: cpp: 142,035; sh: 109; ansic: 26; makefile: 12
file content (174 lines) | stat: -rw-r--r-- 4,798 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# Automatic Enum String Serialization

Glaze supports serializing enums as strings by providing metadata via `glz::meta`. By default, this requires manually specifying each enum value. This guide shows how to use compile-time enum reflection libraries to automatically serialize **all** enums as strings without writing individual metadata for each type.

## The Problem

Glaze serializes enums as integers by default. To serialize as strings, you typically write:

```cpp
enum class Color { Red, Green, Blue };

template <>
struct glz::meta<Color> {
    using enum Color;
    static constexpr auto value = glz::enumerate(Red, Green, Blue);
};
```

This becomes tedious with many enums and must be maintained as enums change.

## The Solution

Glaze's `meta<T>` template supports two members for enum serialization:

- `keys` - An array of string names
- `value` - An array of enum values

Enum reflection libraries can provide these at compile-time, enabling a single generic template that handles all enums automatically.

## Library Options

### magic_enum

[magic_enum](https://github.com/Neargye/magic_enum) is the most widely used enum reflection library.

```cpp
#include <glaze/glaze.hpp>
#include <magic_enum/magic_enum.hpp>

namespace glz {
template <typename T>
   requires std::is_enum_v<T>
struct meta<T> {
   static constexpr auto keys = magic_enum::enum_names<T>();
   static constexpr auto value = magic_enum::enum_values<T>();
};
}
```

**Limitations:**

- Default range is `[-128, 127]`. Extend with:
  ```cpp
  #define MAGIC_ENUM_RANGE_MIN 0
  #define MAGIC_ENUM_RANGE_MAX 256
  ```
- Can increase compile times on large projects

### enchantum

[enchantum](https://github.com/ZXShady/enchantum) focuses on faster compile times than magic_enum.

```cpp
#include <glaze/glaze.hpp>
#include <enchantum/enchantum.hpp>
#include <enchantum/entries.hpp>

namespace glz {
template <typename T>
   requires std::is_enum_v<T>
struct meta<T> {
   static constexpr auto keys = enchantum::names<T>;
   static constexpr auto value = enchantum::values<T>;
};
}
```

**Advantages:**

- Significantly faster compile times than magic_enum
- Smaller binary sizes

### simple_enum

[simple_enum](https://github.com/arturbac/simple_enum) provides native Glaze integration for Glaze 5.x.

For Glaze 5.x, simple_enum's built-in integration handles everything automatically. For newer Glaze versions, you can use the same pattern:

```cpp
#include <glaze/glaze.hpp>
#include <simple_enum/simple_enum.hpp>

namespace glz {
template <typename T>
   requires std::is_enum_v<T>
struct meta<T> {
   static constexpr auto keys = simple_enum::enum_names_array_v<T>;
   static constexpr auto value = simple_enum::enum_values_array_v<T>;
};
}
```

**Advantages:**

- Bounded enumeration support for efficient compile times
- Native Glaze 5.x integration

## Example Usage

With any of the above integrations in place:

```cpp
enum class Status { Active, Inactive, Pending };
enum class Priority : int { Low = 1, Medium = 5, High = 10 };

struct Task {
   std::string name;
   Status status;
   Priority priority;
};

int main() {
   Task task{"My Task", Status::Active, Priority::High};

   auto json = glz::write_json(task).value();
   // Result: {"name":"My Task","status":"Active","priority":"High"}

   Task parsed{};
   glz::read_json(parsed, json);
   // Correctly parses strings back to enum values
}
```

## Supported Features

These integrations work with:

- **Scoped enums** (`enum class`)
- **Unscoped enums** (`enum`)
- **Sparse enums** (non-sequential values)
- **Enums in containers** (`std::vector<MyEnum>`, `std::map<MyEnum, T>`)
- **Enums in structs**

## Overriding for Specific Enums

If you need custom names for a specific enum, define an explicit specialization:

```cpp
enum class HttpStatus { OK = 200, NotFound = 404 };

// Custom names override the generic template
template <>
struct glz::meta<HttpStatus> {
   static constexpr std::array keys{"200 OK", "404 Not Found"};
   static constexpr std::array value{HttpStatus::OK, HttpStatus::NotFound};
};
```

## Choosing a Library

| Library | Compile Time | Range Limits | Notes |
|---------|--------------|--------------|-------|
| magic_enum | Slower | [-128, 127] default | Most popular, well-documented |
| enchantum | Faster | Configurable | Optimized for compile time |
| simple_enum | Fast | Bounded enums | Native Glaze 5.x support |

For projects with many enums or where compile time matters, consider enchantum or simple_enum. For smaller projects or maximum compatibility, magic_enum is a safe choice.

## See Also

- [Glaze enum documentation](json.md#enums)
- [magic_enum](https://github.com/Neargye/magic_enum)
- [enchantum](https://github.com/ZXShady/enchantum)
- [simple_enum](https://github.com/arturbac/simple_enum)