fix: compile error when deserializing into types using ordered_map#5128
fix: compile error when deserializing into types using ordered_map#5128ssam18 wants to merge 4 commits intonlohmann:developfrom
Conversation
🔴 Amalgamation check failed! 🔴The source code has not been amalgamated. @ssam18 |
When passing a json value using brace initialization with a single element
(e.g., `json j{someObj}` or `foo({someJson})`), C++ always prefers the
initializer_list constructor over the copy/move constructor. This caused
the value to be unexpectedly wrapped in a single-element array.
This bug was previously compiler-dependent (GCC wrapped, Clang did not),
but Clang 20 started matching GCC behavior, making it a universal issue.
Fix: In the initializer_list constructor, when type deduction is enabled
and the list has exactly one element, copy/move it directly instead of
creating a single-element array.
Before:
json obj = {{"key", 1}};
json j{obj}; // -> [{"key":1}] (wrong: array)
foo({obj}); // -> [{"key":1}] (wrong: array)
After:
json j{obj}; // -> {"key":1} (correct: copy)
foo({obj}); // -> {"key":1} (correct: copy)
To explicitly create a single-element array, use json::array({value}).
Fixes the issue nlohmann#5074
Signed-off-by: Samaresh Kumar Singh <ssam3003@gmail.com>
std::transform + std::inserter on vector-backed ordered_map triggers element shifting code in GCC's <algorithm>, which requires pair::operator=. That is deleted when the key is const (e.g. ordered_map<string, string>). Replace with a range-for + emplace so no assignment is ever needed. Fix for the bug nlohmann#5122 Signed-off-by: Samaresh Kumar Singh <ssam3003@gmail.com>
Signed-off-by: Samaresh Kumar Singh <ssam3003@gmail.com>
6401b3b to
f906482
Compare
🔴 Amalgamation check failed! 🔴The source code has not been amalgamated. @ssam18 |
Signed-off-by: Samaresh Kumar Singh <ssam3003@gmail.com>
🔴 Amalgamation check failed! 🔴The source code has not been amalgamated. @ssam18 |
1 similar comment
🔴 Amalgamation check failed! 🔴The source code has not been amalgamated. @ssam18 |
| yield different results (`#!json [true]` vs. `#!json true`)? | ||
|
|
||
| This is a known issue, and -- even worse -- the behavior differs between GCC and Clang. The "culprit" for this is the library's constructor overloads for initializer lists to allow syntax like | ||
| Starting from this version, single-value brace initialization is treated as copy/move instead of wrapping in a single-element array: |
There was a problem hiding this comment.
This is a breaking change we cannot accept. Please revert.
There was a problem hiding this comment.
I will take a look in a day or two
gregmarr
left a comment
There was a problem hiding this comment.
You need to drop commit 2071ba67d9923f4b5349142dc3d12887572ceb61 from this.
| } | ||
| else | ||
| { | ||
| // if there is exactly one element and type deduction is enabled, |
There was a problem hiding this comment.
This is also that breaking change that we can't accept.
|
|
||
| #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ | ||
| #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ | ||
| #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ |
There was a problem hiding this comment.
There is something wrong with your amalgamation setup.
When deserializing into a struct that contains an
ordered_mapfield (e.g. viaNLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT), GCC fails to compile becausestd::transform+std::insertertriggers the element-shifting path in<algorithm>, which requirespair::operator=deleted when the key isconst.Replaced the transform with a simple range-for loop and
emplace, which constructs in-place and never tries to assign.