diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 7fe19f57..cd6bfd17 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -72,6 +72,23 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) s = *j.template get_ptr(); } +template < + typename BasicJsonType, typename CompatibleStringType, + enable_if_t < + is_compatible_string_type::value and + not std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, CompatibleStringType& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + + s = *j.template get_ptr(); +} + template void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) { diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index f8c31661..64090dcc 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -51,6 +51,16 @@ struct external_constructor j.m_value = std::move(s); j.assert_invariant(); } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleStringType& str) + { + j.m_type = value_t::string; + j.m_value.string = j.template create(str); + j.assert_invariant(); + } }; template<> diff --git a/include/nlohmann/detail/meta.hpp b/include/nlohmann/detail/meta.hpp index b251afb6..50200304 100644 --- a/include/nlohmann/detail/meta.hpp +++ b/include/nlohmann/detail/meta.hpp @@ -120,6 +120,17 @@ struct is_compatible_object_type_impl std::is_constructible::value; }; +template +struct is_compatible_string_type_impl : std::false_type {}; + +template +struct is_compatible_string_type_impl +{ + static constexpr auto value = + std::is_same::value and + std::is_constructible::value; +}; + template struct is_compatible_object_type { @@ -130,6 +141,15 @@ struct is_compatible_object_type typename BasicJsonType::object_t, CompatibleObjectType >::value; }; +template +struct is_compatible_string_type +{ + static auto constexpr value = is_compatible_string_type_impl < + conjunction>, + has_value_type>::value, + typename BasicJsonType::string_t, CompatibleStringType >::value; +}; + template struct is_basic_json_nested_type { diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index cac7805a..5cd7c01e 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -2829,9 +2829,9 @@ class basic_json not detail::is_basic_json::value #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same>::value -#endif -#if defined(JSON_HAS_CPP_17) +#if defined(JSON_HAS_CPP_17) && _MSC_VER <= 1914 and not std::is_same::value +#endif #endif , int >::type = 0 > operator ValueType() const diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index f4fc1fda..fa60301c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -354,6 +354,17 @@ struct is_compatible_object_type_impl std::is_constructible::value; }; +template +struct is_compatible_string_type_impl : std::false_type {}; + +template +struct is_compatible_string_type_impl +{ + static constexpr auto value = + std::is_same::value and + std::is_constructible::value; +}; + template struct is_compatible_object_type { @@ -364,6 +375,15 @@ struct is_compatible_object_type typename BasicJsonType::object_t, CompatibleObjectType >::value; }; +template +struct is_compatible_string_type +{ + static auto constexpr value = is_compatible_string_type_impl < + conjunction>, + has_value_type>::value, + typename BasicJsonType::string_t, CompatibleStringType >::value; +}; + template struct is_basic_json_nested_type { @@ -980,6 +1000,23 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) s = *j.template get_ptr(); } +template < + typename BasicJsonType, typename CompatibleStringType, + enable_if_t < + is_compatible_string_type::value and + not std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, CompatibleStringType& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + + s = *j.template get_ptr(); +} + template void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) { @@ -1324,6 +1361,16 @@ struct external_constructor j.m_value = std::move(s); j.assert_invariant(); } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleStringType& str) + { + j.m_type = value_t::string; + j.m_value.string = j.template create(str); + j.assert_invariant(); + } }; template<> @@ -13588,9 +13635,9 @@ class basic_json not detail::is_basic_json::value #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same>::value -#endif -#if defined(JSON_HAS_CPP_17) +#if defined(JSON_HAS_CPP_17) && _MSC_VER <= 1914 and not std::is_same::value +#endif #endif , int >::type = 0 > operator ValueType() const diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index df9a6c18..5b6dea22 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -40,6 +40,17 @@ using nlohmann::json; #include #include +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +#if defined(JSON_HAS_CPP_17) +#include +#endif + TEST_CASE("value conversion") { SECTION("get an object (explicit)") @@ -344,6 +355,13 @@ TEST_CASE("value conversion") std::string s = j.get(); CHECK(json(s) == j); } +#if defined(JSON_HAS_CPP_17) + SECTION("std::string_view") + { + std::string_view s = j.get(); + CHECK(json(s) == j); + } +#endif SECTION("exception in case of a non-string type") { @@ -385,6 +403,34 @@ TEST_CASE("value conversion") json(json::value_t::number_float).get(), "[json.exception.type_error.302] type must be string, but is number"); } + +#if defined(JSON_HAS_CPP_17) + SECTION("exception in case of a non-string type using string_view") + { + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + + CHECK_THROWS_WITH(json(json::value_t::null).get(), + "[json.exception.type_error.302] type must be string, but is null"); + CHECK_THROWS_WITH(json(json::value_t::object).get(), + "[json.exception.type_error.302] type must be string, but is object"); + CHECK_THROWS_WITH(json(json::value_t::array).get(), + "[json.exception.type_error.302] type must be string, but is array"); + CHECK_THROWS_WITH(json(json::value_t::boolean).get(), + "[json.exception.type_error.302] type must be string, but is boolean"); + CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), + "[json.exception.type_error.302] type must be string, but is number"); + CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), + "[json.exception.type_error.302] type must be string, but is number"); + CHECK_THROWS_WITH(json(json::value_t::number_float).get(), + "[json.exception.type_error.302] type must be string, but is number"); + } +#endif } SECTION("get a string (implicit)") @@ -398,6 +444,14 @@ TEST_CASE("value conversion") CHECK(json(s) == j); } +#if defined(JSON_HAS_CPP_17) + SECTION("std::string_view") + { + std::string_view s = j; + CHECK(json(s) == j); + } +#endif + SECTION("std::string") { std::string s = j;