Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
21 changes: 21 additions & 0 deletions include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions tests/src/unit-comparison.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading