mirror of
https://github.com/nlohmann/json.git
synced 2026-09-30 19:50:34 +00:00
Add scalar-on-left overloads for legacy discarded comparisons in C++20
With JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1 and C++20, a scalar on the left-hand side of <= or >= (e.g., `1 <= discarded`) yielded false instead of the documented true. The C++20 legacy block only had member operators, which are only candidates when the basic_json is the left operand; for a scalar on the left, overload resolution picked the candidate rewritten from operator<=>, which does not emulate the legacy behavior. The C++17 branch already has scalar-on-the-left friend overloads for <= and >=; add the equivalent pair to the C++20 legacy block. Added a regression test to tests/src/unit-comparison.cpp covering all four operand orders for both operators. Fixes #5665. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -79,3 +79,6 @@ When the macro is not defined, the library will define it to its default value.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.11.0.
|
||||
- Fixed in version 3.13.0 so `<=` and `>=` also emulate the legacy behavior in C++20 when the JSON value is the
|
||||
right-hand operand of a scalar comparison; before, only the 3-way-comparison-rewritten candidate was found, which
|
||||
yielded `#!cpp false` instead of `#!cpp true`.
|
||||
|
||||
@@ -4673,6 +4673,27 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return *this >= basic_json(rhs);
|
||||
}
|
||||
|
||||
// a scalar on the left-hand side would otherwise select the candidate
|
||||
// rewritten from operator<=>, which does not emulate the legacy behavior
|
||||
|
||||
/// @brief comparison: less than or equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
|
||||
{
|
||||
return basic_json(lhs) <= rhs;
|
||||
}
|
||||
|
||||
/// @brief comparison: greater than or equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
|
||||
{
|
||||
return basic_json(lhs) >= rhs;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
/// @brief comparison: equal
|
||||
|
||||
@@ -30754,6 +30754,27 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return *this >= basic_json(rhs);
|
||||
}
|
||||
|
||||
// a scalar on the left-hand side would otherwise select the candidate
|
||||
// rewritten from operator<=>, which does not emulate the legacy behavior
|
||||
|
||||
/// @brief comparison: less than or equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
|
||||
{
|
||||
return basic_json(lhs) <= rhs;
|
||||
}
|
||||
|
||||
/// @brief comparison: greater than or equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
|
||||
{
|
||||
return basic_json(lhs) >= rhs;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
/// @brief comparison: equal
|
||||
|
||||
@@ -749,6 +749,28 @@ TEST_CASE("regression #3868 - heterogeneous comparisons compile under C++20 (P24
|
||||
CHECK_FALSE(j != i);
|
||||
}
|
||||
}
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
TEST_CASE("regression #5665 - scalar <= discarded and scalar >= discarded in C++20 legacy mode")
|
||||
{
|
||||
// Issue #5665: with a scalar on the left-hand side, <= and >= only had the
|
||||
// candidate rewritten from operator<=>, which does not emulate the legacy
|
||||
// discarded-value behavior. Check that scalar-on-the-left now matches the
|
||||
// other three operand orders.
|
||||
const json discarded(json::value_t::discarded);
|
||||
const json one = 1;
|
||||
|
||||
CHECK(discarded <= 1);
|
||||
CHECK(discarded >= 1);
|
||||
CHECK(one <= discarded);
|
||||
CHECK(one >= discarded);
|
||||
CHECK(1 <= discarded);
|
||||
CHECK(1 >= discarded);
|
||||
CHECK(1.5 <= discarded);
|
||||
CHECK(1.5 >= discarded);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace
|
||||
|
||||
Reference in New Issue
Block a user