diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 797f714df..3a24a6f4d 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -539,7 +539,10 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p) JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); } const auto& s = *j.template get_ptr(); -#ifdef JSON_HAS_CPP_20 + // Checking for C++20 standard or later can be insufficient in case the + // library support for char8_t is either incomplete or was disabled + // altogether. Use the __cpp_lib_char8_t feature test instead. +#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L) p = std_fs::path(std::u8string_view(reinterpret_cast(s.data()), s.size())); #else p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index f8413850d..8b910dd16 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -15,7 +15,8 @@ #include // copy #include // begin, end -#include // string +#include // allocator_traits +#include // basic_string, char_traits #include // tuple, get #include // is_same, is_constructible, is_floating_point, is_enum, underlying_type #include // move, forward, declval, pair @@ -440,15 +441,21 @@ inline void to_json(BasicJsonType& j, const T& t) } #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +#if defined(__cpp_lib_char8_t) +template +inline void to_json(BasicJsonType& j, const std::basic_string& s) +{ + using OtherAllocator = typename std::allocator_traits::template rebind_alloc; + j = std::basic_string, OtherAllocator>(s.begin(), s.end(), s.get_allocator()); +} +#endif + template inline void to_json(BasicJsonType& j, const std_fs::path& p) { -#ifdef JSON_HAS_CPP_20 - const std::u8string s = p.u8string(); - j = std::string(s.begin(), s.end()); -#else - j = p.u8string(); // returns std::string in C++17 -#endif + // Returns either a std::string or a std::u8string depending whether library + // support for char8_t is enabled. + j = p.u8string(); } #endif diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 13b07c0fb..93e5983cf 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5324,7 +5324,10 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p) JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); } const auto& s = *j.template get_ptr(); -#ifdef JSON_HAS_CPP_20 + // Checking for C++20 standard or later can be insufficient in case the + // library support for char8_t is either incomplete or was disabled + // altogether. Use the __cpp_lib_char8_t feature test instead. +#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L) p = std_fs::path(std::u8string_view(reinterpret_cast(s.data()), s.size())); #else p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 @@ -5379,7 +5382,8 @@ NLOHMANN_JSON_NAMESPACE_END #include // copy #include // begin, end -#include // string +#include // allocator_traits +#include // basic_string, char_traits #include // tuple, get #include // is_same, is_constructible, is_floating_point, is_enum, underlying_type #include // move, forward, declval, pair @@ -6086,15 +6090,21 @@ inline void to_json(BasicJsonType& j, const T& t) } #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +#if defined(__cpp_lib_char8_t) +template +inline void to_json(BasicJsonType& j, const std::basic_string& s) +{ + using OtherAllocator = typename std::allocator_traits::template rebind_alloc; + j = std::basic_string, OtherAllocator>(s.begin(), s.end(), s.get_allocator()); +} +#endif + template inline void to_json(BasicJsonType& j, const std_fs::path& p) { -#ifdef JSON_HAS_CPP_20 - const std::u8string s = p.u8string(); - j = std::string(s.begin(), s.end()); -#else - j = p.u8string(); // returns std::string in C++17 -#endif + // Returns either a std::string or a std::u8string depending whether library + // support for char8_t is enabled. + j = p.u8string(); } #endif diff --git a/tests/src/unit-deserialization.cpp b/tests/src/unit-deserialization.cpp index 84a970a18..5c450c23d 100644 --- a/tests/src/unit-deserialization.cpp +++ b/tests/src/unit-deserialization.cpp @@ -1134,9 +1134,10 @@ TEST_CASE("deserialization") } } -// select the types to test - char8_t is only available in C++20 +// select the types to test - char8_t is only available since C++20 if and only +// if __cpp_char8_t is defined. #define TYPE_LIST(...) __VA_ARGS__ -#ifdef JSON_HAS_CPP_20 +#if defined(__cpp_char8_t) && (__cpp_char8_t >= 201811L) #define ASCII_TYPES TYPE_LIST(char, wchar_t, char16_t, char32_t, char8_t) #else #define ASCII_TYPES TYPE_LIST(char, wchar_t, char16_t, char32_t)