diff --git a/docs/mkdocs/docs/api/basic_json/basic_json.md b/docs/mkdocs/docs/api/basic_json/basic_json.md index dadb2d887..f5c861712 100644 --- a/docs/mkdocs/docs/api/basic_json/basic_json.md +++ b/docs/mkdocs/docs/api/basic_json/basic_json.md @@ -93,10 +93,18 @@ basic_json(basic_json&& other) noexcept; The constructor tries to convert the internal `m_value` of the parameter. Each member value (object, array, string, etc.) is serialized via the corresponding `to_json()` overload. For objects and strings, the conversion requires that the *target* `basic_json` type's `object_t::key_type` (or `string_t`) be directly constructible from the - *source* type's corresponding member type via `is_constructible`. If this requirement is not met, the conversion - does not fail to compile; instead, it silently falls back to the array-conversion path, which represents objects - as arrays of `[key, value]` pairs and strings as arrays of character codes. This is a known limitation tracked in - [issue #3425](https://github.com/nlohmann/json/issues/3425). + *source* type's corresponding member type via `is_constructible`. If this requirement is not met, the result + depends on the *source* string type: + + - If it is a range of characters (it has `begin()` and `end()`, as `std::string` does), the conversion falls back to + the array-conversion path, which represents objects as arrays of `[key, value]` pairs and strings as arrays of + character codes. This result has a different type than the source value, so the constructor's + [`JSON_ASSERT`](../macros/json_assert.md) fails; with its default definition, `assert`, the program aborts unless + `NDEBUG` is defined, in which case the array is returned. + - Otherwise, the conversion does not compile, even though `#!cpp std::is_constructible` reports `#!cpp true`; for + example, when converting a `basic_json` whose `string_t` is the `alt_string` of the unit tests to `json`. + + This is a known limitation tracked in [issue #3425](https://github.com/nlohmann/json/issues/3425). 5. Creates a JSON value of type array or object from the passed initializer list `init`. In case `type_deduction` is `#!cpp true` (default), the type of the JSON value to be created is deducted from the initializer list `init` diff --git a/docs/mkdocs/docs/api/basic_json/object_t.md b/docs/mkdocs/docs/api/basic_json/object_t.md index 835d7b185..f75bbeec1 100644 --- a/docs/mkdocs/docs/api/basic_json/object_t.md +++ b/docs/mkdocs/docs/api/basic_json/object_t.md @@ -102,9 +102,12 @@ objects. When converting an object from one `basic_json` specialization to another via the [converting constructor](basic_json.md) (overload 4), the target `object_t`'s `key_type` must be -directly constructible from the source `basic_json`'s `string_t` type (or more generally, from the -source object's key type). If this requirement is not met, the conversion does not fail; instead, -the object is silently converted as an array of key-value pairs, which is incorrect. See +directly constructible from the source object's key type (with the default `std::map`, the source `basic_json`'s +`string_t`). If this requirement is not met and the source string type is a range of characters, the +object is converted as an array of key-value pairs, which is incorrect: the converting constructor's +[`JSON_ASSERT`](../macros/json_assert.md) fails; with its default definition, `assert`, the program aborts unless +`NDEBUG` is defined, in which case the array is returned. If the source string type is not a range of characters, the +conversion does not compile at all. See [`basic_json`](basic_json.md) and [issue #3425](https://github.com/nlohmann/json/issues/3425) for details and an example. ## Examples diff --git a/docs/mkdocs/docs/api/basic_json/string_t.md b/docs/mkdocs/docs/api/basic_json/string_t.md index 1e3a4b2b5..27f0a3aa2 100644 --- a/docs/mkdocs/docs/api/basic_json/string_t.md +++ b/docs/mkdocs/docs/api/basic_json/string_t.md @@ -60,9 +60,11 @@ String values are stored as pointers in a `basic_json` type. That is, for any ac When converting a string value from one `basic_json` specialization to another via the [converting constructor](basic_json.md) (overload 4), the target `string_t` must be directly constructible from the source `basic_json`'s `string_t` type. If this requirement is not met, the -conversion does not fail; instead, the string is silently converted as an array of character codes, -which is incorrect. See [issue #3425](https://github.com/nlohmann/json/issues/3425) for details -and an example. +conversion depends on the source string type. If it is a range of characters, the string is converted as an array of +character codes, which is incorrect: the converting constructor's [`JSON_ASSERT`](../macros/json_assert.md) fails; with +its default definition, `assert`, the program aborts unless `NDEBUG` is defined, in which case the array is returned. +If the source string type is not a range of characters, the conversion does not compile at all. See +[issue #3425](https://github.com/nlohmann/json/issues/3425) for details and an example. ## Examples diff --git a/docs/mkdocs/docs/features/types/template_parameters.md b/docs/mkdocs/docs/features/types/template_parameters.md index 6ae6820f5..9c3479ab0 100644 --- a/docs/mkdocs/docs/features/types/template_parameters.md +++ b/docs/mkdocs/docs/features/types/template_parameters.md @@ -28,15 +28,16 @@ Requirements are split into two groups: [`BinaryType`](#binarytype)'s `value_type`, and [`NumberUnsignedType`](#numberintegertype-and-numberunsignedtype) being at least as wide as [`NumberIntegerType`](#numberintegertype-and-numberunsignedtype). The rest are not diagnosed with dedicated error messages, and violating most of them results in a compiler error somewhere inside - the library. Four violations are not caught at compile time at all: + the library. Four violations are not (always) caught at compile time: - A [`StringType`](#stringtype) whose `data()` is not null-terminated compiles and silently misparses numbers stored as a `#!cpp long double` that is not IEEE 754 binary64 (e.g., the 80-bit x87 format), because the lexer hands the buffer to `#!cpp std::strtold`. - A stateful [`AllocatorType`](#allocatortype) compiles and silently ignores its state: allocation, deallocation, and [`get_allocator()`](../../api/basic_json/get_allocator.md) each use a different default-constructed instance. - - The two [cross-specialization conversions](#cross-specialization-conversions) below. These abort on an assertion - in a normal build, and only fail silently under `#!cpp NDEBUG`. + - The two [cross-specialization conversions](#cross-specialization-conversions) below, when the source string type + is a range of characters. They compile and fail the `#!cpp JSON_ASSERT`: with its default definition, the program + aborts unless `#!cpp NDEBUG` is defined, in which case the wrong result is returned silently. ## Overview @@ -765,14 +766,18 @@ See [`json_base_class_t`](../../api/basic_json/json_base_class_t.md) for an exam ## Cross-specialization conversions Converting a value from one `basic_json` specialization into another (see the -[converting constructor](../../api/basic_json/basic_json.md)) imposes two additional requirements that are not -diagnosed at compile time. With assertions enabled they abort on the `#!cpp JSON_ASSERT` at the end of the converting -constructor; under `#!cpp NDEBUG` they fail **silently** at runtime: +[converting constructor](../../api/basic_json/basic_json.md)) imposes two additional requirements: -- The target `string_t` must be directly constructible from the source `string_t`. Otherwise the string is converted to - an array of character codes. -- The target `object_t::key_type` must be directly constructible from the source object's key type. Otherwise the - object is converted to an array of key/value pairs. +- The target `string_t` must be directly constructible from the source `string_t`. +- The target `object_t::key_type` must be directly constructible from the source object's key type. + +If a requirement is not met, the result depends on the source string type. If it is a range of characters (it has +`begin()` and `end()`, as `std::string` does), the conversion compiles and then fails the `#!cpp JSON_ASSERT` at the +end of the converting constructor: with its default definition, `assert`, the program aborts unless `#!cpp NDEBUG` is +defined, in which case it **silently** returns an array (of character codes for a string, of key/value pairs for an +object). Otherwise, the conversion does not compile, even though +`#!cpp std::is_constructible` reports `#!cpp true`; for example, when converting a `basic_json` whose `string_t` is the +`alt_string` of the unit tests to `json`. See [issue #3425](https://github.com/nlohmann/json/issues/3425), [`string_t`](../../api/basic_json/string_t.md), and [`object_t`](../../api/basic_json/object_t.md).