diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 07b625a89..d877663dd 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1441,7 +1441,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec be destroyed. */ template - void convert_iteratively(const BasicJsonType& val) + void convert_iteratively(const BasicJsonType& val, std::true_type /*unused*/) { using other_const_iterator = typename BasicJsonType::const_iterator; @@ -1535,21 +1535,38 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (JSON_HEDLEY_LIKELY(guard.okay())) { - // every element comes back to the converting constructor - if (val.is_object()) - { - using other_object_t = typename BasicJsonType::object_t; - JSONSerializer::to_json(*this, val.template get_ref()); - } - else - { - using other_array_t = typename BasicJsonType::array_t; - JSONSerializer::to_json(*this, val.template get_ref()); - } + convert_by_serializers(val); return; } - convert_iteratively(val); + // the iterative conversion needs to construct this object type's keys + // from those of @a val; if it cannot, neither can the range constructor, + // and the serializers convert @a val some other way (see #3425) + convert_iteratively(val, std::is_constructible {}); + } + + /// @brief convert the object or array @a val with the serializers; every + /// element comes back to the converting constructor + template + void convert_by_serializers(const BasicJsonType& val) + { + if (val.is_object()) + { + using other_object_t = typename BasicJsonType::object_t; + JSONSerializer::to_json(*this, val.template get_ref()); + } + else + { + using other_array_t = typename BasicJsonType::array_t; + JSONSerializer::to_json(*this, val.template get_ref()); + } + } + + /// @brief convert @a val whose keys cannot be converted, see @ref convert_structured + template + void convert_iteratively(const BasicJsonType& val, std::false_type /*unused*/) + { + convert_by_serializers(val); } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 16e87cc86..2b3a074ca 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -27978,7 +27978,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec be destroyed. */ template - void convert_iteratively(const BasicJsonType& val) + void convert_iteratively(const BasicJsonType& val, std::true_type /*unused*/) { using other_const_iterator = typename BasicJsonType::const_iterator; @@ -28072,21 +28072,38 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec if (JSON_HEDLEY_LIKELY(guard.okay())) { - // every element comes back to the converting constructor - if (val.is_object()) - { - using other_object_t = typename BasicJsonType::object_t; - JSONSerializer::to_json(*this, val.template get_ref()); - } - else - { - using other_array_t = typename BasicJsonType::array_t; - JSONSerializer::to_json(*this, val.template get_ref()); - } + convert_by_serializers(val); return; } - convert_iteratively(val); + // the iterative conversion needs to construct this object type's keys + // from those of @a val; if it cannot, neither can the range constructor, + // and the serializers convert @a val some other way (see #3425) + convert_iteratively(val, std::is_constructible {}); + } + + /// @brief convert the object or array @a val with the serializers; every + /// element comes back to the converting constructor + template + void convert_by_serializers(const BasicJsonType& val) + { + if (val.is_object()) + { + using other_object_t = typename BasicJsonType::object_t; + JSONSerializer::to_json(*this, val.template get_ref()); + } + else + { + using other_array_t = typename BasicJsonType::array_t; + JSONSerializer::to_json(*this, val.template get_ref()); + } + } + + /// @brief convert @a val whose keys cannot be converted, see @ref convert_structured + template + void convert_iteratively(const BasicJsonType& val, std::false_type /*unused*/) + { + convert_by_serializers(val); }