docs: qualify push_back({value}) and += {value} brace-init behavior (#6091)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
b5967d0ff9
commit
abab6f2f76
4 files changed
+58
-3
No files matched your search
@@ -27,6 +27,16 @@ reference operator+=(initializer_list_t init);
|
|||||||
`init` is converted into an object element and added using `operator+=(const typename object_t::value_type&)`.
|
`init` is converted into an object element and added using `operator+=(const typename object_t::value_type&)`.
|
||||||
Otherwise, `init` is converted to a JSON value and added using `operator+=(basic_json&&)`.
|
Otherwise, `init` is converted to a JSON value and added using `operator+=(basic_json&&)`.
|
||||||
|
|
||||||
|
!!! note "Single braced JSON value"
|
||||||
|
|
||||||
|
For a call such as `#!cpp arr += {obj}`, where the initializer list contains a single JSON value `obj`,
|
||||||
|
compilers may disagree unless
|
||||||
|
[`JSON_BRACE_INIT_COPY_SEMANTICS`](../macros/json_brace_init_copy_semantics.md) is defined to `1`: GCC, for
|
||||||
|
example, selects this overload and appends a single-element array `[obj]`, whereas Clang selects the
|
||||||
|
`basic_json` overload and appends a copy of `obj`. With the macro, GCC and Clang both append a copy of `obj`.
|
||||||
|
To get a portable result without the macro, write `#!cpp arr += obj` to append a copy, or
|
||||||
|
`#!cpp arr += json::array({obj})` to append a single-element array.
|
||||||
|
|
||||||
## Iterator invalidation
|
## Iterator invalidation
|
||||||
|
|
||||||
For all cases where an element is added to an **array**, a reallocation can happen, in which case all iterators (including
|
For all cases where an element is added to an **array**, a reallocation can happen, in which case all iterators (including
|
||||||
|
|||||||
@@ -27,6 +27,16 @@ void push_back(initializer_list_t init);
|
|||||||
`init` is converted into an object element and added using `push_back(const typename object_t::value_type&)`.
|
`init` is converted into an object element and added using `push_back(const typename object_t::value_type&)`.
|
||||||
Otherwise, `init` is converted to a JSON value and added using `push_back(basic_json&&)`.
|
Otherwise, `init` is converted to a JSON value and added using `push_back(basic_json&&)`.
|
||||||
|
|
||||||
|
!!! note "Single braced JSON value"
|
||||||
|
|
||||||
|
For a call such as `#!cpp arr.push_back({obj})`, where the initializer list contains a single JSON value `obj`,
|
||||||
|
compilers may disagree unless
|
||||||
|
[`JSON_BRACE_INIT_COPY_SEMANTICS`](../macros/json_brace_init_copy_semantics.md) is defined to `1`: GCC, for
|
||||||
|
example, selects this overload and appends a single-element array `[obj]`, whereas Clang selects the
|
||||||
|
`basic_json` overload and appends a copy of `obj`. With the macro, GCC and Clang both append a copy of `obj`.
|
||||||
|
To get a portable result without the macro, write `#!cpp arr.push_back(obj)` to append a copy, or
|
||||||
|
`#!cpp arr.push_back(json::array({obj}))` to append a single-element array.
|
||||||
|
|
||||||
## Iterator invalidation
|
## Iterator invalidation
|
||||||
|
|
||||||
For all cases where an element is added to an **array**, a reallocation can happen, in which case all iterators (including
|
For all cases where an element is added to an **array**, a reallocation can happen, in which case all iterators (including
|
||||||
|
|||||||
@@ -27,9 +27,13 @@ The default value is `0` (disabled — existing behavior is preserved).
|
|||||||
json j{obj};
|
json j{obj};
|
||||||
```
|
```
|
||||||
|
|
||||||
creates a single-element **array** `[{"key":"value"}]` instead of a copy of `obj`. This behavior is
|
creates a single-element **array** `[{"key":"value"}]` instead of a copy of `obj`. For this constructor, the
|
||||||
compiler-dependent for older compilers (GCC wrapped, Clang did not), but starting from Clang 20, both compilers
|
behavior was compiler-dependent for older compilers (GCC wrapped, Clang did not), but starting from Clang 20, both
|
||||||
behave the same way.
|
compilers behave the same way.
|
||||||
|
|
||||||
|
The calls `#!cpp arr.push_back({obj})` and `#!cpp arr += {obj}` are still compiler-dependent without the macro,
|
||||||
|
even with Clang 20 and later: GCC converts `{obj}` to a single-element array and appends that array, whereas Clang
|
||||||
|
appends a copy of `obj`. With the macro defined to `1`, both compilers append a copy of `obj`.
|
||||||
|
|
||||||
Enabling this macro opts into copy/move semantics for this case
|
Enabling this macro opts into copy/move semantics for this case
|
||||||
(see [#5074](https://github.com/nlohmann/json/issues/5074)).
|
(see [#5074](https://github.com/nlohmann/json/issues/5074)).
|
||||||
|
|||||||
@@ -94,6 +94,37 @@ TEST_CASE("JSON_BRACE_INIT_COPY_SEMANTICS")
|
|||||||
CHECK(j3 == pair_shaped);
|
CHECK(j3 == pair_shaped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("push_back and operator+= with a single braced JSON value")
|
||||||
|
{
|
||||||
|
// with the macro, the result does not depend on the compiler;
|
||||||
|
// without it, GCC wraps a JSON value and Clang does not (a literal
|
||||||
|
// such as {1} is wrapped by both)
|
||||||
|
json const obj = {{"key", "value"}};
|
||||||
|
json const arr = {1, 2};
|
||||||
|
|
||||||
|
json a1 = json::array();
|
||||||
|
a1.push_back({obj});
|
||||||
|
CHECK(a1 == json::array({obj}));
|
||||||
|
|
||||||
|
json a2 = json::array();
|
||||||
|
a2 += {obj};
|
||||||
|
CHECK(a2 == json::array({obj}));
|
||||||
|
|
||||||
|
json b1 = json::array();
|
||||||
|
b1.push_back({arr});
|
||||||
|
CHECK(b1 == json::array({arr}));
|
||||||
|
|
||||||
|
json b2 = json::array();
|
||||||
|
b2 += {arr};
|
||||||
|
CHECK(b2 == json::array({arr}));
|
||||||
|
|
||||||
|
// a literal is copied as well
|
||||||
|
json c = json::array();
|
||||||
|
c.push_back({1});
|
||||||
|
c += {2};
|
||||||
|
CHECK(c == json::array({1, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("what the macro does not change")
|
SECTION("what the macro does not change")
|
||||||
{
|
{
|
||||||
// lists with more than one element are unaffected
|
// lists with more than one element are unaffected
|
||||||
|
|||||||
Reference in new issue
Block a user