JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS¶
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS /* value */
When defined to 1, maps whose keys are enums (such as std::map<E, T> or std::unordered_map<E, T>) are stored as JSON objects, using the enum's own conversion for the keys. By default, they are stored as arrays of [key, value] pairs.
Default definition¶
The default value is 0 (disabled — existing behavior is preserved).
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0
Notes¶
Background
JSON object keys are strings, so a map is only stored as an object if its keys can be converted to a string type. Enums are not, even if NLOHMANN_JSON_SERIALIZE_ENUM maps them to strings, so a map with enum keys becomes an array of [key, value] pairs:
[["stopped", "aa"], ["completed", "bb"]]
With this macro, the same map becomes an object (see #4378):
{"completed": "bb", "stopped": "aa"}
Maps with non-unique keys
Maps that allow duplicate keys, such as std::multimap<E, T> or std::unordered_multimap<E, T>, are not affected by the macro and are still stored as arrays of [key, value] pairs, as an object cannot hold duplicate keys.
Reading
Reading is not affected by the macro: a map with enum keys can always be read from both an array of pairs and an object. For the latter, each key is converted to the enum with its from_json function, e.g., the one defined by NLOHMANN_JSON_SERIALIZE_ENUM. Data written without the macro can therefore still be read after enabling it.
Keys must serialize to distinct strings
Each key is converted with the enum's to_json function. If a key is not converted to a string (for instance, an enum without NLOHMANN_JSON_SERIALIZE_ENUM, which is stored as an integer, or an enumerator mapped to nullptr), type_error.302 is thrown. If two keys are converted to the same string (for instance, because NLOHMANN_JSON_SERIALIZE_ENUM maps an unlisted enumerator to the first entry), type_error.318 is thrown. In both cases, the target value is not changed.
Opt-in only
This macro must be defined before including <nlohmann/json.hpp>. Defining it after the include has no effect.
ABI compatibility
The value of this macro is encoded in the namespace (tag _ekmo), resulting in distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program without One Definition Rule (ODR) violations, but they cannot exchange instances of library types.
Examples¶
Default behavior (macro not defined)
Without the macro, a map with enum keys is stored as an array of pairs:
#include <map>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
enum TaskState { TS_STOPPED, TS_RUNNING, TS_COMPLETED };
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, {
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"},
{TS_COMPLETED, "completed"},
})
int main()
{
std::map<TaskState, std::string> m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
json j = m;
// j is [["stopped","aa"],["completed","bb"]]
}
Objects for enum-keyed maps (macro defined to 1)
With the macro, the same map is stored as an object:
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 1
#include <map>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
enum TaskState { TS_STOPPED, TS_RUNNING, TS_COMPLETED };
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, {
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"},
{TS_COMPLETED, "completed"},
})
int main()
{
std::map<TaskState, std::string> m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
json j = m;
// j is {"completed":"bb","stopped":"aa"}
auto m2 = j.get<std::map<TaskState, std::string>>();
// m2 == m
}
See also¶
- Specializing enum conversion
- NLOHMANN_JSON_SERIALIZE_ENUM - serialize/deserialize an enum
- NLOHMANN_JSON_SERIALIZE_ENUM_STRICT - serialize/deserialize an enum with exceptions
Version history¶
- Added in version 3.13.0 unreleased.