Compare commits

...
Author SHA1 Message Date
Niels Lohmann 1f086dec2b Skip deleted-function detection checks on MSVC 2015
MSVC 2015 does not treat selecting a deleted function in decltype as a
substitution failure, so the detection traits in
unit-delete_deprecated_functions (#5755) and the integral-key checks in
unit-element_access2 (#5657) report deleted overloads as callable there.
Calling them still fails to compile. Skip those checks for
_MSC_VER < 1910, and use the stream operators for real in the runtime
section, so MSVC 2015 still compiles them with the macro set.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 14:58:12 +02:00
Niels Lohmann 336c808485 Skip the #5650 allocator test on MSVC 2015 debug builds
MSVC 2015's debug STL constructs the containers' debug proxies through
the allocator in noexcept constructors, so countdown_allocator's failing
construction crashes test-allocator (SIGSEGV) instead of throwing
std::bad_alloc. Use the guard #5585 uses for the same reason.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 13:49:28 +02:00
Niels Lohmann 556027f109 Avoid MSVC 2015's C4800 for enums with underlying type bool
MSVC 2015 warns about any conversion to bool (C4800), even with an
explicit cast, so the enum conversions from #5754 (#5671) failed the
AppVeyor build with /WX. Convert to bool by comparing with zero via the
new detail::bool_aware_static_cast, and keep doctest from printing the
enum in the test.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 13:29:32 +02:00
Niels Lohmann 413dd2d2c9 Re-amalgamate
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 13:00:09 +02:00
Niels Lohmann 98eff63537 Fix the AppVeyor (MSVC 2015-2019) build
- binary_reader: emit_signed/emit_unsigned pass integers that do not fit
  the number types to emit_float as long double, because MSVC's <cmath>
  has no integer overloads of std::isfinite (C2668 'fpclassify'), from #5607
- scalar comparisons: the friend operators take the JSON type for their
  noexcept from their parameter, because MSVC 2015/2017 take basic_json as
  the class template there (C3203) and MSVC 2019 16.0 does not see member
  types or template parameters, from #5751
- unit-conversions2: skip the !is_nothrow_constructible static_assert for
  std::optional on MSVC 2017, which evaluates the conditional noexcept as
  true (C2607), from #5754

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 12:57:44 +02:00
Niels Lohmann f88e209ea9 Ignore libstdc++'s <format> sign change in the sanitizer job
libstdc++ 14's <format> initializes a size_t parameter with -1 (GCC bug
119429), so every std::format call fails ci_test_clang_sanitizer under
-fsanitize=integer (test-std-format_cpp20). Exclude only the
implicit-integer-sign-change check and only that header via
-fsanitize-ignorelist.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 12:36:10 +02:00
Niels Lohmann d5a1c5d149 Fix CI on develop after #5600, #5607, and #5755
- binary_reader: cast the result of -1 - number back to number_integer_t,
  because a number_integer_t narrower than int is promoted to int, which
  GCC's -Warith-conversion rejects (ci_test_gcc, ci_test_standards_gcc)
- JSON_DELETE_DEPRECATED_FUNCTIONS: declare the deleted stream operators
  as function templates at namespace scope, because GCC < 5 rejects deleted
  friend functions ("can't initialize friend function") and Clang 7-9 report
  a redefinition when a class template has a deleted friend function
- docs: give the examples of JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS "Example:"
  titles and add the page to the docset (style_check)

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-05 10:37:17 +02:00
14 changed files with 170 additions and 59 deletions
+1 -1
View File
@@ -376,7 +376,7 @@ add_custom_target(ci_test_coverage
# Sanitizers. # Sanitizers.
############################################################################### ###############################################################################
set(CLANG_CXX_FLAGS_SANITIZER "-g -O1 -fsanitize=address -fsanitize=undefined -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer -fno-sanitize-recover=all -fno-sanitize=unsigned-integer-overflow -fno-sanitize=unsigned-shift-base") set(CLANG_CXX_FLAGS_SANITIZER "-g -O1 -fsanitize=address -fsanitize=undefined -fsanitize=integer -fsanitize=nullability -fno-omit-frame-pointer -fno-sanitize-recover=all -fno-sanitize=unsigned-integer-overflow -fno-sanitize=unsigned-shift-base -fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/cmake/clang_sanitizer_ignorelist.txt")
add_custom_target(ci_test_clang_sanitizer add_custom_target(ci_test_clang_sanitizer
COMMAND CXX=${CLANG_TOOL} CXXFLAGS=${CLANG_CXX_FLAGS_SANITIZER} ${CMAKE_COMMAND} COMMAND CXX=${CLANG_TOOL} CXXFLAGS=${CLANG_CXX_FLAGS_SANITIZER} ${CMAKE_COMMAND}
+8
View File
@@ -0,0 +1,8 @@
# Sanitizer ignore list for ci_test_clang_sanitizer (-fsanitize-ignorelist).
#
# libstdc++ 14's <format> declares `_Scanner(basic_string_view<_CharT>, size_t __nargs = -1)`, so every std::format
# call converts -1 to size_t, which -fsanitize=integer reports as implicit-integer-sign-change. This is
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119429, not a bug in this library. Only that check and only <format> are
# excluded, so implicit sign changes in the library and the tests are still reported.
[implicit-integer-sign-change]
src:*/include/c++/*/format
+1
View File
@@ -250,6 +250,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_TRY_USER', 'Macro', 'api
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro', 'api/macros/json_use_global_udls/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro', 'api/macros/json_use_global_udls/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS', 'Macro', 'api/macros/json_use_objects_for_enum_keyed_maps/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_SIMDUTF', 'Macro', 'api/macros/json_use_simdutf/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_SIMDUTF', 'Macro', 'api/macros/json_use_simdutf/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html');
INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html');
@@ -69,7 +69,7 @@ The default value is `0` (disabled — existing behavior is preserved).
## Examples ## Examples
??? example "Default behavior (macro not defined)" ??? example "Example: default behavior (macro not defined)"
Without the macro, a map with enum keys is stored as an array of pairs: Without the macro, a map with enum keys is stored as an array of pairs:
@@ -96,7 +96,7 @@ The default value is `0` (disabled — existing behavior is preserved).
} }
``` ```
??? example "Objects for enum-keyed maps (macro defined to 1)" ??? example "Example: objects for enum-keyed maps (macro defined to 1)"
With the macro, the same map is stored as an object: With the macro, the same map is stored as an object:
@@ -172,7 +172,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
typename BasicJsonType::number_unsigned_t, underlying_type>::type; typename BasicJsonType::number_unsigned_t, underlying_type>::type;
value_type val; value_type val;
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
e = static_cast<EnumType>(static_cast<underlying_type>(val)); e = static_cast<EnumType>(bool_aware_static_cast<underlying_type>(val));
} }
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
@@ -365,7 +365,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept
{ {
using underlying_type = typename std::underlying_type<EnumType>::type; using underlying_type = typename std::underlying_type<EnumType>::type;
static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer; static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer;
external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e)); external_constructor<integral_value_t>::construct(j, bool_aware_static_cast<underlying_type>(e));
} }
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
@@ -662,10 +662,11 @@ class binary_reader
} }
// the value is -1 - number, which fits into number_integer_t // the value is -1 - number, which fits into number_integer_t
// whenever number does // whenever number does; the outer cast undoes the integral promotion
// for number_integer_t types narrower than int
if (JSON_HEDLEY_LIKELY(value_in_range_of<number_integer_t>(number))) if (JSON_HEDLEY_LIKELY(value_in_range_of<number_integer_t>(number)))
{ {
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)); return sax->number_integer(conditional_static_cast<number_integer_t>(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)));
} }
// like the lexer does for JSON text, store a value too small for // like the lexer does for JSON text, store a value too small for
@@ -4003,7 +4004,8 @@ class binary_reader
{ {
return sax->number_unsigned(static_cast<number_unsigned_t>(number)); return sax->number_unsigned(static_cast<number_unsigned_t>(number));
} }
return emit_float(number); // std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
} }
/*! /*!
@@ -4026,7 +4028,8 @@ class binary_reader
{ {
return sax->number_unsigned(static_cast<number_unsigned_t>(number)); return sax->number_unsigned(static_cast<number_unsigned_t>(number));
} }
return emit_float(number); // std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
} }
/*! /*!
@@ -4037,7 +4040,8 @@ class binary_reader
and NaN in the input are passed on unchanged. Integers only overflow if and NaN in the input are passed on unchanged. Integers only overflow if
number_float_t cannot represent 2^64, e.g., a half-precision type. number_float_t cannot represent 2^64, e.g., a half-precision type.
@tparam NumberType a floating-point or integer type @tparam NumberType a floating-point type (emit_signed and emit_unsigned
convert integers to long double first)
@param[in] number the number @param[in] number the number
@return whether the SAX parser accepted the value @return whether the SAX parser accepted the value
@@ -906,6 +906,21 @@ T conditional_static_cast(U value)
return value; return value;
} }
// like conditional_static_cast, but converts to bool by comparing with zero,
// because MSVC 2015 warns about any conversion to bool (C4800), even with an
// explicit cast; used for enums whose underlying type is bool
template < typename T, typename U, enable_if_t < !std::is_same<T, bool>::value, int > = 0 >
T bool_aware_static_cast(U value)
{
return conditional_static_cast<T>(value);
}
template<typename T, typename U, enable_if_t<std::is_same<T, bool>::value, int> = 0>
bool bool_aware_static_cast(U value)
{
return value != U();
}
template<typename... Types> template<typename... Types>
using all_integral = conjunction<std::is_integral<Types>...>; using all_integral = conjunction<std::is_integral<Types>...>;
+37 -20
View File
@@ -5098,7 +5098,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -5107,7 +5107,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
@@ -5128,11 +5128,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#endif #endif
} }
// The friend comparisons with a scalar name the JSON type via decltype of
// their parameter in noexcept, because older MSVC versions do not see the
// class scope there: MSVC 2015 and 2017 take basic_json as the template,
// and MSVC 2019 16.0 rejects member types and template parameters.
/// @brief comparison: equal /// @brief comparison: equal
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs == basic_json(rhs); return lhs == basic_json(rhs);
} }
@@ -5141,7 +5146,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) == rhs; return basic_json(lhs) == rhs;
} }
@@ -5157,7 +5162,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs != basic_json(rhs); return lhs != basic_json(rhs);
} }
@@ -5166,7 +5171,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) != rhs; return basic_json(lhs) != rhs;
} }
@@ -5186,7 +5191,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs < basic_json(rhs); return lhs < basic_json(rhs);
} }
@@ -5195,7 +5200,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) < rhs; return basic_json(lhs) < rhs;
} }
@@ -5215,7 +5220,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs <= basic_json(rhs); return lhs <= basic_json(rhs);
} }
@@ -5224,7 +5229,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -5245,7 +5250,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs > basic_json(rhs); return lhs > basic_json(rhs);
} }
@@ -5254,7 +5259,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) > rhs; return basic_json(lhs) > rhs;
} }
@@ -5274,7 +5279,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs >= basic_json(rhs); return lhs >= basic_json(rhs);
} }
@@ -5283,7 +5288,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
@@ -5319,6 +5324,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return o; return o;
} }
#if !JSON_DELETE_DEPRECATED_FUNCTIONS
// the deleted version is a function template after the class, because
// GCC < 5 and Clang < 10 reject deleted friend functions in class templates
/// @brief serialize to stream /// @brief serialize to stream
/// @sa https://json.nlohmann.me/api/operator_ltlt/ /// @sa https://json.nlohmann.me/api/operator_ltlt/
/// @deprecated This function is deprecated since 3.0.0 and will be removed in /// @deprecated This function is deprecated since 3.0.0 and will be removed in
@@ -5327,9 +5335,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// replace calls like `j >> o;` with `o << j;`. /// replace calls like `j >> o;` with `o << j;`.
JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
friend std::ostream& operator>>(const basic_json& j, std::ostream& o) friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return o << j; return o << j;
} }
@@ -5507,6 +5512,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
#if !JSON_DELETE_DEPRECATED_FUNCTIONS
// the deleted version is a function template after the class, because
// GCC < 5 and Clang < 10 reject deleted friend functions in class templates
/// @brief deserialize from stream /// @brief deserialize from stream
/// @sa https://json.nlohmann.me/api/operator_gtgt/ /// @sa https://json.nlohmann.me/api/operator_gtgt/
/// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
@@ -5515,9 +5523,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// replace calls like `j << i;` with `i >> j;`. /// replace calls like `j << i;` with `i >> j;`.
JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
friend std::istream& operator<<(basic_json& j, std::istream& i) friend std::istream& operator<<(basic_json& j, std::istream& i)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return operator>>(i, j); return operator>>(i, j);
} }
@@ -7178,6 +7183,18 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j)
return j.dump(); return j.dump();
} }
#if JSON_DELETE_DEPRECATED_FUNCTIONS && !defined(JSON_NO_IO)
/// @brief serialize to stream (deleted; use operator<<(std::ostream&, const basic_json&))
/// @sa https://json.nlohmann.me/api/operator_ltlt/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::ostream& operator>>(const NLOHMANN_BASIC_JSON_TPL& j, std::ostream& o) = delete;
/// @brief deserialize from stream (deleted; use operator>>(std::istream&, basic_json&))
/// @sa https://json.nlohmann.me/api/operator_gtgt/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::istream& operator<<(NLOHMANN_BASIC_JSON_TPL& j, std::istream& i) = delete;
#endif
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
/////////////////////// ///////////////////////
+63 -27
View File
@@ -4905,6 +4905,21 @@ T conditional_static_cast(U value)
return value; return value;
} }
// like conditional_static_cast, but converts to bool by comparing with zero,
// because MSVC 2015 warns about any conversion to bool (C4800), even with an
// explicit cast; used for enums whose underlying type is bool
template < typename T, typename U, enable_if_t < !std::is_same<T, bool>::value, int > = 0 >
T bool_aware_static_cast(U value)
{
return conditional_static_cast<T>(value);
}
template<typename T, typename U, enable_if_t<std::is_same<T, bool>::value, int> = 0>
bool bool_aware_static_cast(U value)
{
return value != U();
}
template<typename... Types> template<typename... Types>
using all_integral = conjunction<std::is_integral<Types>...>; using all_integral = conjunction<std::is_integral<Types>...>;
@@ -5700,7 +5715,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
typename BasicJsonType::number_unsigned_t, underlying_type>::type; typename BasicJsonType::number_unsigned_t, underlying_type>::type;
value_type val; value_type val;
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
e = static_cast<EnumType>(static_cast<underlying_type>(val)); e = static_cast<EnumType>(bool_aware_static_cast<underlying_type>(val));
} }
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
@@ -7144,7 +7159,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept
{ {
using underlying_type = typename std::underlying_type<EnumType>::type; using underlying_type = typename std::underlying_type<EnumType>::type;
static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer; static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer;
external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e)); external_constructor<integral_value_t>::construct(j, bool_aware_static_cast<underlying_type>(e));
} }
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
@@ -14353,10 +14368,11 @@ class binary_reader
} }
// the value is -1 - number, which fits into number_integer_t // the value is -1 - number, which fits into number_integer_t
// whenever number does // whenever number does; the outer cast undoes the integral promotion
// for number_integer_t types narrower than int
if (JSON_HEDLEY_LIKELY(value_in_range_of<number_integer_t>(number))) if (JSON_HEDLEY_LIKELY(value_in_range_of<number_integer_t>(number)))
{ {
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)); return sax->number_integer(conditional_static_cast<number_integer_t>(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)));
} }
// like the lexer does for JSON text, store a value too small for // like the lexer does for JSON text, store a value too small for
@@ -17694,7 +17710,8 @@ class binary_reader
{ {
return sax->number_unsigned(static_cast<number_unsigned_t>(number)); return sax->number_unsigned(static_cast<number_unsigned_t>(number));
} }
return emit_float(number); // std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
} }
/*! /*!
@@ -17717,7 +17734,8 @@ class binary_reader
{ {
return sax->number_unsigned(static_cast<number_unsigned_t>(number)); return sax->number_unsigned(static_cast<number_unsigned_t>(number));
} }
return emit_float(number); // std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
} }
/*! /*!
@@ -17728,7 +17746,8 @@ class binary_reader
and NaN in the input are passed on unchanged. Integers only overflow if and NaN in the input are passed on unchanged. Integers only overflow if
number_float_t cannot represent 2^64, e.g., a half-precision type. number_float_t cannot represent 2^64, e.g., a half-precision type.
@tparam NumberType a floating-point or integer type @tparam NumberType a floating-point type (emit_signed and emit_unsigned
convert integers to long double first)
@param[in] number the number @param[in] number the number
@return whether the SAX parser accepted the value @return whether the SAX parser accepted the value
@@ -32248,7 +32267,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -32257,7 +32276,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
@@ -32278,11 +32297,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#endif #endif
} }
// The friend comparisons with a scalar name the JSON type via decltype of
// their parameter in noexcept, because older MSVC versions do not see the
// class scope there: MSVC 2015 and 2017 take basic_json as the template,
// and MSVC 2019 16.0 rejects member types and template parameters.
/// @brief comparison: equal /// @brief comparison: equal
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs == basic_json(rhs); return lhs == basic_json(rhs);
} }
@@ -32291,7 +32315,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) == rhs; return basic_json(lhs) == rhs;
} }
@@ -32307,7 +32331,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs != basic_json(rhs); return lhs != basic_json(rhs);
} }
@@ -32316,7 +32340,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) != rhs; return basic_json(lhs) != rhs;
} }
@@ -32336,7 +32360,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs < basic_json(rhs); return lhs < basic_json(rhs);
} }
@@ -32345,7 +32369,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) < rhs; return basic_json(lhs) < rhs;
} }
@@ -32365,7 +32389,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs <= basic_json(rhs); return lhs <= basic_json(rhs);
} }
@@ -32374,7 +32398,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; return basic_json(lhs) <= rhs;
} }
@@ -32395,7 +32419,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs > basic_json(rhs); return lhs > basic_json(rhs);
} }
@@ -32404,7 +32428,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) > rhs; return basic_json(lhs) > rhs;
} }
@@ -32424,7 +32448,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{ {
return lhs >= basic_json(rhs); return lhs >= basic_json(rhs);
} }
@@ -32433,7 +32457,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if< template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value) friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
@@ -32469,6 +32493,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return o; return o;
} }
#if !JSON_DELETE_DEPRECATED_FUNCTIONS
// the deleted version is a function template after the class, because
// GCC < 5 and Clang < 10 reject deleted friend functions in class templates
/// @brief serialize to stream /// @brief serialize to stream
/// @sa https://json.nlohmann.me/api/operator_ltlt/ /// @sa https://json.nlohmann.me/api/operator_ltlt/
/// @deprecated This function is deprecated since 3.0.0 and will be removed in /// @deprecated This function is deprecated since 3.0.0 and will be removed in
@@ -32477,9 +32504,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// replace calls like `j >> o;` with `o << j;`. /// replace calls like `j >> o;` with `o << j;`.
JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
friend std::ostream& operator>>(const basic_json& j, std::ostream& o) friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return o << j; return o << j;
} }
@@ -32657,6 +32681,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
#if !JSON_DELETE_DEPRECATED_FUNCTIONS
// the deleted version is a function template after the class, because
// GCC < 5 and Clang < 10 reject deleted friend functions in class templates
/// @brief deserialize from stream /// @brief deserialize from stream
/// @sa https://json.nlohmann.me/api/operator_gtgt/ /// @sa https://json.nlohmann.me/api/operator_gtgt/
/// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
@@ -32665,9 +32692,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// replace calls like `j << i;` with `i >> j;`. /// replace calls like `j << i;` with `i >> j;`.
JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
friend std::istream& operator<<(basic_json& j, std::istream& i) friend std::istream& operator<<(basic_json& j, std::istream& i)
#if JSON_DELETE_DEPRECATED_FUNCTIONS
= delete;
#else
{ {
return operator>>(i, j); return operator>>(i, j);
} }
@@ -34328,6 +34352,18 @@ std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j)
return j.dump(); return j.dump();
} }
#if JSON_DELETE_DEPRECATED_FUNCTIONS && !defined(JSON_NO_IO)
/// @brief serialize to stream (deleted; use operator<<(std::ostream&, const basic_json&))
/// @sa https://json.nlohmann.me/api/operator_ltlt/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::ostream& operator>>(const NLOHMANN_BASIC_JSON_TPL& j, std::ostream& o) = delete;
/// @brief deserialize from stream (deleted; use operator>>(std::istream&, basic_json&))
/// @sa https://json.nlohmann.me/api/operator_gtgt/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::istream& operator<<(NLOHMANN_BASIC_JSON_TPL& j, std::istream& i) = delete;
#endif
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
/////////////////////// ///////////////////////
+5
View File
@@ -521,6 +521,10 @@ struct countdown_allocator : std::allocator<T>
TEST_CASE("converting a deeply nested value from another specialization fails cleanly (#5650)") TEST_CASE("converting a deeply nested value from another specialization fails cleanly (#5650)")
{ {
// MSVC 2015's debug STL constructs the containers' debug proxies through
// the allocator in noexcept constructors, so a failing construction crashes
// the program there instead of throwing std::bad_alloc. Nothing to check.
#if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
using countdown_json = nlohmann::basic_json<std::map, using countdown_json = nlohmann::basic_json<std::map,
std::vector, std::vector,
std::string, std::string,
@@ -558,6 +562,7 @@ TEST_CASE("converting a deeply nested value from another specialization fails cl
} }
} }
CHECK(failures > 0); CHECK(failures > 0);
#endif
} }
namespace namespace
+7 -2
View File
@@ -191,8 +191,10 @@ TEST_CASE("value conversion")
{ {
enum class bool_enum : bool { off, on }; enum class bool_enum : bool { off, on };
CHECK(json(bool_enum::off).get<bool_enum>() == bool_enum::off); // the extra parentheses keep doctest from printing the enum via its
CHECK(json(bool_enum::on).get<bool_enum>() == bool_enum::on); // underlying type, which MSVC 2015 reports as C4800
CHECK((json(bool_enum::off).get<bool_enum>() == bool_enum::off));
CHECK((json(bool_enum::on).get<bool_enum>() == bool_enum::on));
} }
#endif #endif
@@ -851,7 +853,10 @@ TEST_CASE("std::optional")
CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&); CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&);
// the conversion is noexcept exactly when converting the contained value is // the conversion is noexcept exactly when converting the contained value is
// (MSVC 2017 evaluates the conditional noexcept of this conversion as true)
#if !defined(_MSC_VER) || _MSC_VER >= 1920
static_assert(!std::is_nothrow_constructible<json, const std::optional<throwing_to_json_type>&>::value); static_assert(!std::is_nothrow_constructible<json, const std::optional<throwing_to_json_type>&>::value);
#endif
static_assert(std::is_nothrow_constructible<json, const std::optional<int>&>::value); static_assert(std::is_nothrow_constructible<json, const std::optional<int>&>::value);
} }
#endif #endif
@@ -22,6 +22,7 @@ using nlohmann::json;
#include <cstdint> #include <cstdint>
#include <istream> #include <istream>
#include <ostream> #include <ostream>
#include <sstream>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -109,6 +110,10 @@ JSON_TEST_DETECT(ptr_at, std::declval<J&>().at(std::declval<const typename J::js
TEST_CASE("JSON_DELETE_DEPRECATED_FUNCTIONS") TEST_CASE("JSON_DELETE_DEPRECATED_FUNCTIONS")
{ {
// MSVC 2015 does not treat selecting a deleted function in decltype as a
// substitution failure, so the traits cannot tell deleted functions apart
// there; calling them still fails to compile
#if !(defined(_MSC_VER) && _MSC_VER < 1910)
SECTION("from_* with a pointer and a length") SECTION("from_* with a pointer and a length")
{ {
// the overloads are deleted rather than removed, so the length cannot // the overloads are deleted rather than removed, so the length cannot
@@ -197,6 +202,8 @@ TEST_CASE("JSON_DELETE_DEPRECATED_FUNCTIONS")
CHECK(ptr_at<json>::value); CHECK(ptr_at<json>::value);
} }
#endif
SECTION("the non-deprecated functions still work") SECTION("the non-deprecated functions still work")
{ {
const json j = {{"a", {1, 2}}}; const json j = {{"a", {1, 2}}};
@@ -210,5 +217,13 @@ TEST_CASE("JSON_DELETE_DEPRECATED_FUNCTIONS")
CHECK(j.at(ptr) == 2); CHECK(j.at(ptr) == 2);
CHECK(j.value(ptr, 0) == 2); CHECK(j.value(ptr, 0) == 2);
CHECK(j.contains(ptr)); CHECK(j.contains(ptr));
std::ostringstream os;
os << j;
CHECK(os.str() == R"({"a":[1,2]})");
std::istringstream is(os.str());
json parsed;
is >> parsed;
CHECK(parsed == j);
} }
} }
+5
View File
@@ -1551,6 +1551,10 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j
// count(0) used to compile and then crash instead of failing to compile // count(0) used to compile and then crash instead of failing to compile
using nlohmann::detail::is_detected; using nlohmann::detail::is_detected;
// MSVC 2015 does not treat selecting a deleted function in decltype as
// a substitution failure, so it detects the deleted overloads as
// callable; calling them still fails to compile
#if !(defined(_MSC_VER) && _MSC_VER < 1910)
CHECK_FALSE(is_detected<can_call_find_with_0, Json&>::value); CHECK_FALSE(is_detected<can_call_find_with_0, Json&>::value);
CHECK_FALSE(is_detected<can_call_find_with_0, const Json&>::value); CHECK_FALSE(is_detected<can_call_find_with_0, const Json&>::value);
CHECK_FALSE(is_detected<can_call_count_with_0, Json&>::value); CHECK_FALSE(is_detected<can_call_count_with_0, Json&>::value);
@@ -1562,6 +1566,7 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j
// another integral literal type must be rejected as well, not just int // another integral literal type must be rejected as well, not just int
CHECK_FALSE(is_detected<can_call_contains_with_0L, Json&>::value); CHECK_FALSE(is_detected<can_call_contains_with_0L, Json&>::value);
#endif
// the valid overloads must remain callable // the valid overloads must remain callable
CHECK(is_detected<can_call_find, Json&, const char*>::value); CHECK(is_detected<can_call_find, Json&, const char*>::value);