From e0eb3e7490579172d08db9403798be63785b91f6 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 27 Sep 2026 18:31:22 +0200 Subject: [PATCH] Construct explicitly in get_to() and to_json(std::optional) With JSON_USE_IMPLICIT_CONVERSIONS=0 the conversion from a basic_json with a different string type is now explicit, but two library paths still assigned such a value implicitly and failed to compile inside the library: - get_to() with a basic_json target (the #2175 overload) did `v = *this`, so json(42).get_to(alt_json&) broke although get() works. - to_json(BasicJsonType&, const std::optional&) is constrained on std::is_constructible (which accepts the explicit constructor) but did `j = *opt`, so converting a std::optional into a json broke. Both now construct the value explicitly, as get_impl() already does. Also replace static_cast(JSON_USE_IMPLICIT_CONVERSIONS) with a comparison: clang-tidy's modernize-use-bool-literals rejected the cast of the integer literal the macro expands to, failing ci_clang_tidy. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/conversions/to_json.hpp | 4 +++- include/nlohmann/json.hpp | 4 ++-- single_include/nlohmann/json.hpp | 8 +++++--- tests/src/unit-alt-string.cpp | 5 +++++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 491bb9873..c13493499 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -291,7 +291,9 @@ void to_json(BasicJsonType& j, const std::optional& opt) noexcept { if (opt.has_value()) { - j = *opt; + // explicit construction, as the conversion from a basic_json with a different + // string type is explicit if JSON_USE_IMPLICIT_CONVERSIONS is 0 (#2649) + j = BasicJsonType(*opt); } else { diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index d930cf444..afa18a657 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1611,7 +1611,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// the same string type (see https://github.com/nlohmann/json/issues/2649) template using is_implicitly_convertible_basic_json = std::integral_constant < bool, - static_cast(JSON_USE_IMPLICIT_CONVERSIONS) + (JSON_USE_IMPLICIT_CONVERSIONS != 0) || std::is_same::value >; /// tag to select the constructor that performs the conversion from another basic_json specialization @@ -2602,7 +2602,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec int> = 0> ValueType & get_to(ValueType& v) const { - v = *this; + v = ValueType(*this); return v; } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0231d4694..7e601813e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -6820,7 +6820,9 @@ void to_json(BasicJsonType& j, const std::optional& opt) noexcept { if (opt.has_value()) { - j = *opt; + // explicit construction, as the conversion from a basic_json with a different + // string type is explicit if JSON_USE_IMPLICIT_CONVERSIONS is 0 (#2649) + j = BasicJsonType(*opt); } else { @@ -26492,7 +26494,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// the same string type (see https://github.com/nlohmann/json/issues/2649) template using is_implicitly_convertible_basic_json = std::integral_constant < bool, - static_cast(JSON_USE_IMPLICIT_CONVERSIONS) + (JSON_USE_IMPLICIT_CONVERSIONS != 0) || std::is_same::value >; /// tag to select the constructor that performs the conversion from another basic_json specialization @@ -27483,7 +27485,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec int> = 0> ValueType & get_to(ValueType& v) const { - v = *this; + v = ValueType(*this); return v; } diff --git a/tests/src/unit-alt-string.cpp b/tests/src/unit-alt-string.cpp index 55c1d754f..1e23b478b 100644 --- a/tests/src/unit-alt-string.cpp +++ b/tests/src/unit-alt-string.cpp @@ -403,5 +403,10 @@ TEST_CASE("alternative string type") // (only a number is converted here, as objects and strings are affected by #3425) CHECK(nlohmann::json(42).get() == 42); CHECK(alt_json(nlohmann::json(42)) == 42); + + // get_to() also works in either case + alt_json a; + nlohmann::json(42).get_to(a); + CHECK(a == 42); } }