mirror of
https://github.com/nlohmann/json.git
synced 2026-10-04 21:50:33 +00:00
Make cross-string-type basic_json conversion explicit without implicit conversions
The converting constructor from another basic_json specialization was always implicit, so a value with a different string_t (std::wstring, a string with a custom allocator, ...) silently converted into a temporary, e.g. when passed to a function taking const nlohmann::json&. Such conversions do not produce correct values (#3425), and JSON_USE_IMPLICIT_CONVERSIONS=0 did not catch them. When JSON_USE_IMPLICIT_CONVERSIONS is 0, the constructor is now explicit if the string types differ. Specializations sharing a string type (json and ordered_json, different serializers or object maps) stay implicitly convertible, so the NLOHMANN_DEFINE_TYPE_* macros keep working with nested json members. get<BasicJsonType>() constructs explicitly and works in both modes. Fixes #2649. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -1605,12 +1605,42 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
private:
|
||||
/// whether a basic_json specialization can be converted implicitly into this one;
|
||||
/// with JSON_USE_IMPLICIT_CONVERSIONS set to 0, this is only the case if both share
|
||||
/// the same string type (see https://github.com/nlohmann/json/issues/2649)
|
||||
template<typename BasicJsonType>
|
||||
using is_implicitly_convertible_basic_json = std::integral_constant < bool,
|
||||
static_cast<bool>(JSON_USE_IMPLICIT_CONVERSIONS)
|
||||
|| std::is_same<typename BasicJsonType::string_t, string_t>::value >;
|
||||
|
||||
/// tag to select the constructor that performs the conversion from another basic_json specialization
|
||||
struct convert_basic_json_tag {};
|
||||
|
||||
public:
|
||||
/// @brief create a JSON value from an existing one
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
template < typename BasicJsonType,
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||
&& is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||
basic_json(const BasicJsonType& val)
|
||||
: basic_json(val, convert_basic_json_tag{})
|
||||
{}
|
||||
|
||||
/// @brief create a JSON value from an existing one
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
template < typename BasicJsonType,
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||
&& !is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||
explicit basic_json(const BasicJsonType& val)
|
||||
: basic_json(val, convert_basic_json_tag{})
|
||||
{}
|
||||
|
||||
private:
|
||||
template<typename BasicJsonType>
|
||||
basic_json(const BasicJsonType& val, convert_basic_json_tag /*unused*/)
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
: start_position(val.start_pos()),
|
||||
end_position(val.end_pos())
|
||||
@@ -1666,6 +1696,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
public:
|
||||
/// @brief create a container (array or object) from an initializer list
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
basic_json(initializer_list_t init,
|
||||
@@ -2432,7 +2463,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
int > = 0 >
|
||||
BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return *this;
|
||||
return BasicJsonType(*this);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
Reference in New Issue
Block a user