From 556027f1094358369335c762e93a8a9b93aeec4a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 5 Oct 2026 13:29:32 +0200 Subject: [PATCH] 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 --- .../nlohmann/detail/conversions/from_json.hpp | 2 +- .../nlohmann/detail/conversions/to_json.hpp | 2 +- include/nlohmann/detail/meta/type_traits.hpp | 15 +++++++++++++++ single_include/nlohmann/json.hpp | 19 +++++++++++++++++-- tests/src/unit-conversions2.cpp | 6 ++++-- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 53f6d01cf..884ff014a 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -172,7 +172,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e) typename BasicJsonType::number_unsigned_t, underlying_type>::type; value_type val; get_arithmetic_value(j, val); - e = static_cast(static_cast(val)); + e = static_cast(bool_aware_static_cast(val)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 5b332d4e9..d7197f323 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -365,7 +365,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept { using underlying_type = typename std::underlying_type::type; static constexpr value_t integral_value_t = std::is_unsigned::value ? value_t::number_unsigned : value_t::number_integer; - external_constructor::construct(j, static_cast(e)); + external_constructor::construct(j, bool_aware_static_cast(e)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 69ab05f4e..4c90c68a3 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -906,6 +906,21 @@ T conditional_static_cast(U 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::value, int > = 0 > +T bool_aware_static_cast(U value) +{ + return conditional_static_cast(value); +} + +template::value, int> = 0> +bool bool_aware_static_cast(U value) +{ + return value != U(); +} + template using all_integral = conjunction...>; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index a806c2c1b..765095dcb 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4905,6 +4905,21 @@ T conditional_static_cast(U 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::value, int > = 0 > +T bool_aware_static_cast(U value) +{ + return conditional_static_cast(value); +} + +template::value, int> = 0> +bool bool_aware_static_cast(U value) +{ + return value != U(); +} + template using all_integral = conjunction...>; @@ -5700,7 +5715,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e) typename BasicJsonType::number_unsigned_t, underlying_type>::type; value_type val; get_arithmetic_value(j, val); - e = static_cast(static_cast(val)); + e = static_cast(bool_aware_static_cast(val)); } #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::type; static constexpr value_t integral_value_t = std::is_unsigned::value ? value_t::number_unsigned : value_t::number_integer; - external_constructor::construct(j, static_cast(e)); + external_constructor::construct(j, bool_aware_static_cast(e)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION diff --git a/tests/src/unit-conversions2.cpp b/tests/src/unit-conversions2.cpp index 0dd0c6d52..ed3103484 100644 --- a/tests/src/unit-conversions2.cpp +++ b/tests/src/unit-conversions2.cpp @@ -191,8 +191,10 @@ TEST_CASE("value conversion") { enum class bool_enum : bool { off, on }; - CHECK(json(bool_enum::off).get() == bool_enum::off); - CHECK(json(bool_enum::on).get() == bool_enum::on); + // the extra parentheses keep doctest from printing the enum via its + // underlying type, which MSVC 2015 reports as C4800 + CHECK((json(bool_enum::off).get() == bool_enum::off)); + CHECK((json(bool_enum::on).get() == bool_enum::on)); } #endif