From 37073ea8b5f9344190b5a1a063c4f25c77e4f91a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 31 Aug 2026 09:24:17 +0000 Subject: [PATCH] Detect a void-returning erase() through a named trait erase_from_object() distinguished its two overloads with a decltype of a member call written inline in a default template argument. Every other detection in the library goes through the detector machinery in detected.hpp instead -- has_erase_with_key_type is the same question about the same member function -- and the inline form is the one shape older compilers are least reliable about. Express it the same way: detect_erase_with_iterator plus is_detected_exact, both of which the library already relies on elsewhere. No behaviour changes. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/meta/type_traits.hpp | 9 +++++++++ include/nlohmann/json.hpp | 4 ++-- single_include/nlohmann/json.hpp | 13 +++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 350048b87..6f8bf2a3d 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -779,6 +779,15 @@ using has_erase_with_key_type = typename std::conditional < std::true_type, std::false_type >::type; +template +using detect_erase_with_iterator = decltype(std::declval().erase(std::declval())); + +// type trait to check if erase(iterator) returns void instead of the following +// iterator, as the object types that do not compute a successor the caller may +// not need do +template +using erase_returns_void = is_detected_exact; + template using detect_capacity = decltype(std::declval().capacity()); diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 4bbdc3f63..81c309e63 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -788,14 +788,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// (e.g., Abseil's hash maps) return void to avoid computing a successor /// the caller may not need. Compute it before erasing for those. template < typename It, detail::enable_if_t < - !std::is_void().erase(std::declval()))>::value, int > = 0 > + !detail::erase_returns_void::value, int > = 0 > typename object_t::iterator erase_from_object(It pos) { return m_data.m_value.object->erase(pos); } template < typename It, detail::enable_if_t < - std::is_void().erase(std::declval()))>::value, int > = 0 > + detail::erase_returns_void::value, int > = 0 > typename object_t::iterator erase_from_object(It pos) { auto next = std::next(pos); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 77d29d3cb..32825843e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4579,6 +4579,15 @@ using has_erase_with_key_type = typename std::conditional < std::true_type, std::false_type >::type; +template +using detect_erase_with_iterator = decltype(std::declval().erase(std::declval())); + +// type trait to check if erase(iterator) returns void instead of the following +// iterator, as the object types that do not compute a successor the caller may +// not need do +template +using erase_returns_void = is_detected_exact; + template using detect_capacity = decltype(std::declval().capacity()); @@ -22262,14 +22271,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// (e.g., Abseil's hash maps) return void to avoid computing a successor /// the caller may not need. Compute it before erasing for those. template < typename It, detail::enable_if_t < - !std::is_void().erase(std::declval()))>::value, int > = 0 > + !detail::erase_returns_void::value, int > = 0 > typename object_t::iterator erase_from_object(It pos) { return m_data.m_value.object->erase(pos); } template < typename It, detail::enable_if_t < - std::is_void().erase(std::declval()))>::value, int > = 0 > + detail::erase_returns_void::value, int > = 0 > typename object_t::iterator erase_from_object(It pos) { auto next = std::next(pos);