Skip to content

Commit 81ed8d1

Browse files
rotolofNiccolò Iardella
authored andcommitted
Add NLOHMANN_DEFINE_DERIVED_TYPE_* macros (nlohmann#4033)
* Add NLOHMANN_DEFINE_DERIVED_TYPE_* macros * Fix with amalgamate * Add documentation * Fix with amalgamate * Fix with amalgamate --------- Co-authored-by: Niccolò Iardella <[email protected]>
1 parent 1c05dbc commit 81ed8d1

File tree

5 files changed

+356
-43
lines changed

5 files changed

+356
-43
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT
2+
3+
# NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT
4+
5+
```cpp
6+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(type, base_type, member...) // (1)
7+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(type, base_type, member...) // (2)
8+
9+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(type, base_type, member...) // (3)
10+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, base_type, member...) // (4)
11+
```
12+
13+
These macros can be used to simplify the serialization/deserialization of derived types if you want to use a JSON
14+
object as serialization and want to use the member variable names as object keys in that object.
15+
16+
- Macros 1 and 2 are to be defined **inside** the class/struct to create code for.
17+
Like [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](nlohmann_define_type_intrusive.md), they can access private members.
18+
- Macros 3 and 4 are to be defined **outside** the class/struct to create code for, but **inside** its namespace.
19+
Like [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](nlohmann_define_type_non_intrusive.md),
20+
they **cannot** access private members.
21+
22+
23+
The first parameter is the name of the derived class/struct,
24+
the second parameter is the name of the base class/struct and all remaining parameters name the members.
25+
The base type **must** be already serializable/deserializable.
26+
27+
- Macros 1 and 3 will use [`at`](../basic_json/at.md) during deserialization and will throw
28+
[`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if a key is missing in the JSON object.
29+
- Macros 2 and 4 will use [`value`](../basic_json/value.md) during deserialization and fall back to the default value for the
30+
respective type of the member variable if a key in the JSON object is missing. The generated `from_json()` function
31+
default constructs an object and uses its values as the defaults when calling the `value` function.
32+
33+
## Parameters
34+
35+
`type` (in)
36+
: name of the type (class, struct) to serialize/deserialize
37+
38+
`base_type` (in)
39+
: name of the base type (class, struct) `type` is derived from
40+
41+
`member` (in)
42+
: name of the member variable to serialize/deserialize; up to 64 members can be given as comma-separated list
43+
44+
## Default definition
45+
46+
Macros 1 and 2 add two friend functions to the class which take care of the serialization and deserialization:
47+
48+
```cpp
49+
friend void to_json(nlohmann::json&, const type&);
50+
friend void from_json(const nlohmann::json&, type&);
51+
```
52+
53+
Macros 3 and 4 add two functions to the namespace which take care of the serialization and deserialization:
54+
55+
```cpp
56+
void to_json(nlohmann::json&, const type&);
57+
void from_json(const nlohmann::json&, type&);
58+
```
59+
60+
In both cases they call the `to_json`/`from_json` functions of the base type
61+
before serializing/deserializing the members of the derived type:
62+
63+
```cpp
64+
class A { /* ... */ };
65+
class B : public A { /* ... */ };
66+
67+
void to_json(nlohmann::json& j, const B& b) {
68+
nlohmann::to_json(j, static_cast<const A&>(b));
69+
// ...
70+
}
71+
72+
void from_json(const nlohmann::json& j, B& b) {
73+
nlohmann::from_json(j, static_cast<A&>(b));
74+
// ...
75+
}
76+
```
77+
78+
## Notes
79+
80+
!!! info "Prerequisites"
81+
82+
- Macros 1 and 2 have the same prerequisites of NLOHMANN_DEFINE_TYPE_INTRUSIVE.
83+
- Macros 3 and 3 have the same prerequisites of NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE.
84+
- Serialization/deserialization of base types must be defined.
85+
86+
!!! warning "Implementation limits"
87+
88+
- See Implementation limits for NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE.
89+
90+
## Examples
91+
92+
Example of `NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE` usage:
93+
94+
```cpp
95+
class A {
96+
double Aa;
97+
double Ab;
98+
NLOHMANN_DEFINE_TYPE_INTRUSIVE(A, Aa, Ab)
99+
};
100+
101+
class B : public A {
102+
int Ba;
103+
int Bb;
104+
NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(B, A, Ba, Bb)
105+
};
106+
```
107+
108+
## See also
109+
110+
- [NLOHMANN_DEFINE_TYPE_INTRUSIVE / NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT](nlohmann_define_type_intrusive.md)
111+
for similar macros that can be defined _inside_ a non-derived type.
112+
- [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE / NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT](nlohmann_define_type_non_intrusive.md)
113+
for a similar macros that can be defined _outside_ a non-derived type.
114+
- [Arbitrary Type Conversions](../../features/arbitrary_types.md) for an overview.
115+
116+
## Version history
117+
118+
1. Added in version 3.11.x.

include/nlohmann/detail/macro_scope.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,32 @@
425425
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
426426
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
427427

428+
/*!
429+
@brief macro
430+
@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE
431+
@since version 3.11.x
432+
*/
433+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...) \
434+
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
435+
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
436+
437+
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \
438+
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
439+
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
440+
441+
/*!
442+
@brief macro
443+
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE
444+
@since version 3.11.x
445+
*/
446+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...) \
447+
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
448+
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
449+
450+
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \
451+
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
452+
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
453+
428454
// inspired from https://stackoverflow.com/a/26745591
429455
// allows to call any std function as if (e.g. with begin):
430456
// using std::begin; begin(x);

0 commit comments

Comments
 (0)