This commit is contained in:
nlohmann
2026-11-09 18:59:22 +00:00
parent cf8df97ba7
commit eeea067a72
566 changed files with 15370 additions and 2688 deletions
File diff suppressed because one or more lines are too long
+65
View File
@@ -0,0 +1,65 @@
# Writing generic code
## View types
A view's type names its `BasicJsonType` and its [`view_mode`](https://json.nlohmann.me/api/view_mode/index.md): [`json_view`](https://json.nlohmann.me/api/json_view/index.md) is `basic_json_view<json, view_mode::read_only>`, and [`json_editable_view`](https://json.nlohmann.me/api/json_editable_view/index.md) is `basic_json_view<json, view_mode::editable>`. These are different types. The only conversion between them turns a view of a read-only document into a view of an editable document of the same `BasicJsonType`, so a function written for one shortcut accepts few other views:
```
void print_names(json_view v); // accepts neither an ordered_json_view nor a json_editable_view
void print_names(json_editable_view v); // also accepts a json_view, but no ordered_json_view
```
This is the same pitfall as a `to_json`/`from_json` written for `json` instead of any `BasicJsonType`, which then does not work for `ordered_json`. The shortcuts are for declaring documents and views; a function that takes a view names the views it accepts with a template:
```
// views of editable documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::editable> v);
// views of read-only documents only
template<typename BasicJsonType>
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
// views of either document type
template<typename BasicJsonType, view_mode Mode>
void f(basic_json_view<BasicJsonType, Mode> v);
```
Views are passed by value: they are two pointers, cheap to copy, like a `std::string_view`. A `const&` works as well, but a non-`const` reference does not bind to the views that [`root()`](https://json.nlohmann.me/api/basic_json_document/root/index.md), [`operator[]`](https://json.nlohmann.me/api/basic_json_view/operator%5B%5D/index.md), and [`at()`](https://json.nlohmann.me/api/basic_json_view/at/index.md) return, so `f(doc.root())` would not compile.
There is no conversion from an editable view to a read-only one, by design: the mode decides how a view walks the index. A read-only view reads a container in place, while a view of an editable document follows the links that edits leave behind, so a read-only view of an edited document would read stale values. The other direction is safe: a read-only document has no edits, so a view of it [converts](https://json.nlohmann.me/api/basic_json_view/basic_json_view/index.md) to an editable view, which reads it like an editable document before its first edit. A template deduces the mode without conversions, so the template forms above still accept only the modes they name. Views of both modes compare with [`operator==`](https://json.nlohmann.me/api/basic_json_view/operator_eq/index.md).
[`is_json_view<T>`](https://json.nlohmann.me/api/is_json_view/index.md) tells views from other types, for constraints that cannot be written as a `basic_json_view<...>` parameter.
## A `from_json()` that reads views
[`get<T>()`](https://json.nlohmann.me/api/basic_json_view/get/index.md) on a view calls `T`'s `from_json()` with the view itself if that `from_json()` accepts views, and with [`materialize()`](https://json.nlohmann.me/api/basic_json_view/materialize/index.md) otherwise. The `from_json()` functions of the [`NLOHMANN_DEFINE_TYPE_*`](https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/index.md), [`NLOHMANN_DEFINE_DERIVED_TYPE_*`](https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/index.md), and [`NLOHMANN_JSON_SERIALIZE_ENUM`](https://json.nlohmann.me/api/macros/nlohmann_json_serialize_enum/index.md) macros, and those of the library for the standard types, accept views, so these types need nothing else. For decoding the statuses of twitter.json into structs, reading the view is about 5 times faster than `materialize().get<T>()`.
A hand-written `from_json()` reads views if it is constrained to `json` values and views:
```
template < typename J, typename std::enable_if <
nlohmann::is_json_view<J>::value || std::is_same<J, nlohmann::json>::value, int >::type = 0 >
void from_json(const J& j, person& p)
{
p.name = j.at("name").template get<std::string>();
p.age = j.at("age").template get<int>();
}
```
Its body may only use what views and `basic_json` have in common: the type checks, `at()`, `operator[]`, `contains()`, `value()`, `size()`, iteration and `items()`, and `get<T>()`/`get_to()`. An unconstrained `template<typename BasicJsonType> void from_json(const BasicJsonType& j, person& p)`, as in [arbitrary type conversions](https://json.nlohmann.me/features/arbitrary_types/index.md), is never called with a view, as it might use `basic_json` functions a view does not have; such a type is converted through `materialize()`. A `from_json()` for `json` only is converted through `materialize()` as well.
Reading the view and `materialize().get<T>()` give the same result, except for an object with a repeated key; see [Duplicate keys](https://json.nlohmann.me/features/json_view/differences/#duplicate-keys).
`to_json()` is unaffected: it writes `basic_json` values, never views.
## See also
- [Zero-copy JSON views](https://json.nlohmann.me/features/json_view/index.md) - overview
- [`is_json_view`](https://json.nlohmann.me/api/is_json_view/index.md) - type trait to detect views
- [`view_mode`](https://json.nlohmann.me/api/view_mode/index.md) - read-only and editable views
- [Reading values](https://json.nlohmann.me/features/json_view/reading/index.md) - what `get<T>()` converts without materializing
## Version history
- Added in version 3.13.0 unreleased.