docs: document size-mismatch behavior of fixed-size conversions (#5352)
Conversions whose element count is fixed by the destination C++ type --
`std::pair`, `std::tuple`, `std::array<T, N>`, C arrays, and
`std::map`/`std::unordered_map` with a non-string key -- read exactly the
elements they need via `at` and never compare the JSON array's size to
that number. Excess elements are silently discarded, while a shortfall
throws `out_of_range.401` rather than a `type_error`. Neither direction
was documented in `conversions.md`, `get.md`, or `from_json.md`.
The existing warning covered only `std::array` and stated that a too-short
JSON array leaves the remaining elements default-constructed with no
exception thrown; that is not what happens. Generalize it to all
fixed-size destinations and correct the shortfall direction.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
diff --git a/docs/mkdocs/docs/features/conversions.md b/docs/mkdocs/docs/features/conversions.md
index 2a48a05..765c610 100644
--- a/docs/mkdocs/docs/features/conversions.md
+++ b/docs/mkdocs/docs/features/conversions.md
@@ -122,17 +122,34 @@
with a custom `adl_serializer<std::optional<T>>` specialization. Prefer `get<std::optional<T>>()`/`get_to()`
over `static_cast` for optional types.
-!!! warning "Converting to a fixed-size `std::array` does not check length"
+!!! warning "Converting to a fixed-size destination does not check the array size"
- Converting a JSON array to `#!cpp std::array<T, N>` does not check that the JSON array's size matches `N`:
- if the JSON array is longer, the extra elements are silently dropped; if it is shorter, the remaining
- `std::array` elements are left default-constructed. No exception is thrown in either case.
+ Some destination types have a size that is fixed by their C++ type rather than by the JSON value:
+ `#!cpp std::pair<A, B>`, `#!cpp std::tuple<Ts...>`, `#!cpp std::array<T, N>`, C arrays `#!cpp T[N]`, and
+ `#!cpp std::map`/`#!cpp std::unordered_map` with a non-string key type (which is read from an array of
+ two-element arrays). All of them read exactly as many elements as they need via
+ [`at`](../api/basic_json/at.md) and **never compare the JSON array's size to that number**. The two
+ mismatch directions therefore behave differently:
+
+ - The JSON array has **too many** elements: the surplus is **silently discarded**, and no exception is
+ thrown.
+ - The JSON array has **too few** elements: `at` throws
+ [`out_of_range.401`](../home/exceptions.md#jsonexceptionout_of_range401) for the first missing index --
+ an out-of-range error, not a [`type_error`](../home/exceptions.md#type-errors), even though the cause
+ is a shape mismatch.
```cpp
json j = {1, 2, 3, 4, 5};
- auto a = j.get<std::array<int, 3>>(); // {1, 2, 3} -- elements 4 and 5 silently dropped
+
+ auto a = j.get<std::array<int, 3>>(); // {1, 2, 3} -- elements 4 and 5 silently dropped
+ auto p = j.get<std::pair<int, int>>(); // (1, 2) -- elements 3, 4, and 5 silently dropped
+
+ json k = {1};
+ auto q = k.get<std::pair<int, int>>(); // ❌ throws out_of_range.401
```
+ If a size mismatch is an error in your application, check the size yourself before converting.
+
## Omitting a field when serializing `std::optional`
By default, `to_json` for `std::optional<T>` writes either the value or `#!json null` -- there is no built-in way