I had started the same on my side for unordered containers, I'm attaching my WIP (untested).

As you'll see my main concern was to rely on members protected themselves with a feature test macro like __glibcxx_generic_unordered_lookup. I guess that if you did so it means that I'm too caution and that as long as __glibcxx_associative_heterogeneous_erasure is defined then all the others too.

François


On 2/12/26 19:01, Nathan Myers wrote:
Changes in v4:
  - Fix numerous errors revealed by actual testing.

Changes in v3:
  - Skip calls to _M_check_rehashed as redundant when erasing.
  - Fix Changelog: correct PR#, note extra changes.

Changes in v2:
  - Use concept __heterogeneous_hash_key for unordered containers.

Implement the debug versions of new overloads from P2077.

libstdc++-v3/ChangeLog:
        PR libstdc++/117404
        * include/debug/map.h (extract, erase): Define overloads.
        * include/debug/multimap.h: Same.
        * include/debug/multiset.h: Same.
        * include/debug/set.h: Same.
        * include/debug/unordered_map: Same (2x).
        * include/debug/unordered_set: Same (2x), rename some locals.
---
  libstdc++-v3/include/debug/map.h         | 30 ++++++++++++
  libstdc++-v3/include/debug/multimap.h    | 27 +++++++++++
  libstdc++-v3/include/debug/multiset.h    | 27 +++++++++++
  libstdc++-v3/include/debug/set.h         | 30 ++++++++++++
  libstdc++-v3/include/debug/unordered_map | 49 +++++++++++++++++++
  libstdc++-v3/include/debug/unordered_set | 60 +++++++++++++++++++++---
  6 files changed, 217 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/debug/map.h b/libstdc++-v3/include/debug/map.h
index 0fc7afae385..6e18b67e7b2 100644
--- a/libstdc++-v3/include/debug/map.h
+++ b/libstdc++-v3/include/debug/map.h
@@ -476,6 +476,16 @@ namespace __debug
        return {};
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_tree_key<map> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       {
+         const auto __position = find(__key);
+         return __position != end() ? extract(__position) : node_type{};
+       }
+# endif
+
        insert_return_type
        insert(node_type&& __nh)
        {
@@ -538,6 +548,26 @@ namespace __debug
          }
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      // Note that for some types _Kt this may erase more than
+      // one element, such as if _Kt::operator< checks only part
+      // of the key.
+      template <__heterogeneous_tree_key<map> _Kt>
+       size_type
+       erase(_Kt&& __x)
+       {
+         auto __victims = _Base::equal_range(__x);
+         size_type __count = 0;
+         for (auto __victim = __victims.first; __victim != __victims.second;)
+           {
+             this->_M_invalidate_if(_Equal(__victim));
+             _Base::erase(__victim++);
+             ++__count;
+           }
+         return __count;
+       }
+# endif
+
  #if __cplusplus >= 201103L
        iterator
        erase(const_iterator __first, const_iterator __last)
diff --git a/libstdc++-v3/include/debug/multimap.h 
b/libstdc++-v3/include/debug/multimap.h
index 4137186c527..b6458bff2d5 100644
--- a/libstdc++-v3/include/debug/multimap.h
+++ b/libstdc++-v3/include/debug/multimap.h
@@ -360,6 +360,16 @@ namespace __debug
        return {};
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_tree_key<multimap> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       {
+         const auto __position = find(__key);
+         return __position != end() ? extract(__position) : node_type{};
+       }
+# endif
+
        iterator
        insert(node_type&& __nh)
        { return { _Base::insert(std::move(__nh)), this }; }
@@ -420,6 +430,23 @@ namespace __debug
        return __count;
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_tree_key<multimap> _Kt>
+       size_type
+       erase(_Kt&& __x)
+       {
+         auto __victims = _Base::equal_range(__x);
+         size_type __count = 0;
+         for (auto __victim = __victims.first; __victim != __victims.second;)
+           {
+             this->_M_invalidate_if(_Equal(__victim));
+             _Base::erase(__victim++);
+             ++__count;
+           }
+         return __count;
+       }
+# endif
+
  #if __cplusplus >= 201103L
        iterator
        erase(const_iterator __first, const_iterator __last)
diff --git a/libstdc++-v3/include/debug/multiset.h 
b/libstdc++-v3/include/debug/multiset.h
index 6fa499228f5..31d70ba124f 100644
--- a/libstdc++-v3/include/debug/multiset.h
+++ b/libstdc++-v3/include/debug/multiset.h
@@ -331,6 +331,16 @@ namespace __debug
        return {};
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_tree_key<multiset> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       {
+         const auto __position = find(__key);
+         return __position != end() ? extract(__position) : node_type{};
+       }
+#endif
+
        iterator
        insert(node_type&& __nh)
        { return { _Base::insert(std::move(__nh)), this }; }
@@ -387,6 +397,23 @@ namespace __debug
        return __count;
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_tree_key<multiset> _Kt>
+       size_type
+       erase(_Kt&& __x)
+       {
+         auto __victims = _Base::equal_range(__x);
+         size_type __count = 0;
+         for (auto __victim = __victims.first; __victim != __victims.second;)
+           {
+             this->_M_invalidate_if(_Equal(__victim));
+             _Base::erase(__victim++);
+             ++__count;
+           }
+         return __count;
+       }
+# endif
+
  #if __cplusplus >= 201103L
        _GLIBCXX_ABI_TAG_CXX11
        iterator
diff --git a/libstdc++-v3/include/debug/set.h b/libstdc++-v3/include/debug/set.h
index 99701d4a6d7..ec92f6f6448 100644
--- a/libstdc++-v3/include/debug/set.h
+++ b/libstdc++-v3/include/debug/set.h
@@ -340,6 +340,16 @@ namespace __debug
        return {};
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_tree_key<set> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       {
+         const auto __position = find(__key);
+         return __position != end() ? extract(__position) : node_type{};
+       }
+#endif
+
        insert_return_type
        insert(node_type&& __nh)
        {
@@ -398,6 +408,26 @@ namespace __debug
          }
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      // Note that for some types _Kt this may erase more than
+      // one element, such as if _Kt::operator< checks only part
+      // of the key.
+      template <__heterogeneous_tree_key<set> _Kt>
+       size_type
+       erase(_Kt&& __x)
+       {
+         auto __victims = _Base::equal_range(__x);
+         size_type __count = 0;
+         for (auto __victim = __victims.first; __victim != __victims.second;)
+           {
+             this->_M_invalidate_if(_Equal(__victim));
+             _Base::erase(__victim++);
+             ++__count;
+           }
+         return __count;
+       }
+#endif
+
  #if __cplusplus >= 201103L
        _GLIBCXX_ABI_TAG_CXX11
        iterator
diff --git a/libstdc++-v3/include/debug/unordered_map 
b/libstdc++-v3/include/debug/unordered_map
index 4bde18c917b..1383f9b8c99 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -581,6 +581,17 @@ namespace __debug
        return {};
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_hash_key<unordered_map> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       {
+         const auto __position = _Base::find(__key);
+         return __position != _Base::end() ?
+           _M_extract(__position) : node_type{};
+       }
+#endif
+
        insert_return_type
        insert(node_type&& __nh)
        {
@@ -713,6 +724,16 @@ namespace __debug
        return __ret;
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_hash_key<unordered_map> _Kt>
+       size_type
+       erase(_Kt&& __key)
+       {
+         auto __victim = _Base::find(__key);
+         return __victim != _Base::end() ? _M_erase(__victim), 1 : 0;
+       }
+#endif
+
        iterator
        erase(const_iterator __it)
        {
@@ -1381,6 +1402,17 @@ namespace __debug
        return {};
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_hash_key<unordered_multimap> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       {
+         const auto __position = _Base::find(__key);
+         return __position != _Base::end() ?
+           _M_extract(__position) : node_type{};
+       }
+#endif
+
        iterator
        insert(node_type&& __nh)
        { return { _Base::insert(std::move(__nh)), this }; }
@@ -1510,6 +1542,23 @@ namespace __debug
        return __ret;
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_hash_key<unordered_multimap> _Kt>
+       size_type
+       erase(_Kt&& __key)
+       {
+         size_type __count(0);
+         auto __victims = _Base::equal_range(__key);
+         for (auto __victim = __victims.first; __victim != __victims.second;)
+           {
+             _M_invalidate(__victim);
+             __victim = _Base::erase(__victim);
+             ++__count;
+           }
+         return __count;
+       }
+#endif
+
        iterator
        erase(const_iterator __it)
        {
diff --git a/libstdc++-v3/include/debug/unordered_set 
b/libstdc++-v3/include/debug/unordered_set
index de999a76890..95b751ace2f 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -468,6 +468,17 @@ namespace __debug
        return {};
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_hash_key<unordered_set> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       {
+         const auto __position = _Base::find(__key);
+         return __position != _Base::end() ?
+           _M_extract(__position) : node_type{};
+       }
+#endif
+
        insert_return_type
        insert(node_type&& __nh)
        {
@@ -598,6 +609,16 @@ namespace __debug
        return __ret;
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_hash_key<unordered_set> _Kt>
+       size_type
+       erase(_Kt&& __key)
+       {
+         auto __victim = _Base::find(__key);
+         return __victim != _Base::end() ? _M_erase(__victim), 1 : 0;
+       }
+#endif
+
        iterator
        erase(const_iterator __it)
        {
@@ -1202,6 +1223,17 @@ namespace __debug
        return {};
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_hash_key<unordered_multiset> _Kt>
+       node_type
+       extract(const _Kt& __key)
+       {
+         const auto __position = _Base::find(__key);
+         return __position != _Base::end() ?
+           _M_extract(__position) : node_type{};
+       }
+#endif
+
        iterator
        insert(node_type&& __nh)
        { return { _Base::insert(std::move(__nh)), this }; }
@@ -1318,18 +1350,34 @@ namespace __debug
        size_type
        erase(const key_type& __key)
        {
-       size_type __ret(0);
-       auto __pair = _Base::equal_range(__key);
-       for (auto __victim = __pair.first; __victim != __pair.second;)
+       size_type __count(0);
+       auto __victims = _Base::equal_range(__key);
+       for (auto __victim = __victims.first; __victim != __victims.second;)
          {
            _M_invalidate(__victim);
            __victim = _Base::erase(__victim);
-           ++__ret;
+           ++__count;
          }
-
-       return __ret;
+       return __count;
        }
+# ifdef __glibcxx_associative_heterogeneous_erasure
+      template <__heterogeneous_hash_key<unordered_multiset> _Kt>
+       size_type
+       erase(_Kt&& __key)
+       {
+         size_type __count(0);
+         auto __victims = _Base::equal_range(__key);
+         for (auto __victim = __victims.first; __victim != __victims.second;)
+           {
+             _M_invalidate(__victim);
+             __victim = _Base::erase(__victim);
+             ++__count;
+           }
+         return __count;
+       }
+#endif
+
        iterator
        erase(const_iterator __it)
        {
diff --git a/libstdc++-v3/include/bits/unordered_map.h 
b/libstdc++-v3/include/bits/unordered_map.h
index 9b74cba8675..1836dc08178 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -958,7 +958,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       { return _M_h.key_eq(); }
 
       // lookup.
+    protected:
+      // For __gnu_debug container usage.
+      template<typename _Kt>
+       auto
+       _M_find_tr(const _Kt& __x) -> decltype(_M_h._M_find_tr(__x))
+       { return _M_h._M_find_tr(__x); }
 
+    public:
       ///@{
       /**
        *  @brief Tries to locate an element in an %unordered_map.
@@ -2050,7 +2057,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       { return _M_h.key_eq(); }
 
       // lookup.
+    protected:
+      // For __gnu_debug container usage.
+      template<typename _Kt>
+       auto
+       _M_find_tr(const _Kt& __x) -> decltype(_M_h._M_find_tr(__x))
+       { return _M_h._M_find_tr(__x); }
 
+    public:
       ///@{
       /**
        *  @brief Tries to locate an element in an %unordered_multimap.
@@ -2123,6 +2137,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       ///@}
 #endif
 
+    protected:
+      // For __gnu_debug container usage.
+      template<typename _Kt>
+       auto
+       _M_equal_range_tr(const _Kt& __x)
+       -> decltype(_M_h._M_equal_range_tr(__x))
+       { return _M_h._M_equal_range_tr(__x); }
+
+    public:
       ///@{
       /**
        *  @brief Finds a subsequence matching given key.
diff --git a/libstdc++-v3/include/bits/unordered_set.h 
b/libstdc++-v3/include/bits/unordered_set.h
index 22b2ad9caf4..c925e88ba63 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -741,7 +741,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       { return _M_h.key_eq(); }
 
       // lookup.
+    protected:
+      // For __gnu_debug container.
+      template<typename _Kt>
+       auto
+       _M_find_tr(const _Kt& __k) -> decltype(_M_h._M_find_tr(__k))
+       { return _M_h._M_find_tr(__k); }
 
+    public:
       ///@{
       /**
        *  @brief Tries to locate an element in an %unordered_set.
@@ -1831,6 +1838,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       ///@}
 #endif
 
+    protected:
+      // For __gnu_debug container.
+      template<typename _Kt>
+       auto
+       _M_equal_range_tr(const _Kt& __x)
+       -> decltype(_M_h._M_equal_range_tr(__x))
+       { return _M_h._M_equal_range_tr(__x); }
+
+    public:
       ///@{
       /**
        *  @brief Finds a subsequence matching given key.
diff --git a/libstdc++-v3/include/debug/unordered_map 
b/libstdc++-v3/include/debug/unordered_map
index 4bde18c917b..140f200bfc4 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -574,12 +574,14 @@ namespace __debug
 
       node_type
       extract(const key_type& __key)
-      {
-       const auto __position = _Base::find(__key);
-       if (__position != _Base::end())
-         return _M_extract(__position);
-       return {};
-      }
+      { return _M_extract_tr(__key); }
+
+#ifdef __glibcxx_associative_heterogeneous_erasure // C++23
+      template<__heterogeneous_hash_key<unordered_map> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       { return _M_extract_tr(__key); }
+#endif
 
       insert_return_type
       insert(node_type&& __nh)
@@ -702,16 +704,7 @@ namespace __debug
 
       size_type
       erase(const key_type& __key)
-      {
-       size_type __ret(0);
-       auto __victim = _Base::find(__key);
-       if (__victim != _Base::end())
-         {
-           _M_erase(__victim);
-           __ret = 1;
-         }
-       return __ret;
-      }
+      { return _M_erase_tr(__key); }
 
       iterator
       erase(const_iterator __it)
@@ -753,6 +746,13 @@ namespace __debug
        return { __next, this };
       }
 
+#ifdef __glibcxx_associative_heterogeneous_erasure // C++23
+      template<__heterogeneous_hash_key<unordered_map> _Kt>
+       size_type
+       erase(_Kt&& __key)
+       { return _M_erase_tr(__key); }
+#endif
+
       using _Base::rehash;
       using _Base::reserve;
 
@@ -780,6 +780,20 @@ namespace __debug
          { return __it == __victim; });
       }
 
+      template<typename _Kt>
+       size_type
+       _M_erase_tr(const _Kt& __key)
+       {
+         size_type __ret(0);
+         auto __victim = this->_M_find_tr(__key);
+         if (__victim != _Base::end())
+           {
+             _M_erase(__victim);
+             __ret = 1;
+           }
+         return __ret;
+       }
+
       _Base_iterator
       _M_erase(_Base_const_iterator __victim)
       {
@@ -791,6 +805,16 @@ namespace __debug
       }
 
 #ifdef __glibcxx_node_extract // >= C++17 && HOSTED
+      template<typename _Kt>
+       node_type
+       extract(const _Kt& __key)
+       {
+         const auto __position = this->_M_find_tr(__key);
+         if (__position != _Base::end())
+           return _M_extract(__position);
+         return {};
+       }
+
       node_type
       _M_extract(_Base_const_iterator __victim)
       {
@@ -1374,12 +1398,14 @@ namespace __debug
 
       node_type
       extract(const key_type& __key)
-      {
-       const auto __position = _Base::find(__key);
-       if (__position != _Base::end())
-         return _M_extract(__position);
-       return {};
-      }
+      { return _M_extract_tr(__key); }
+
+#ifdef __glibcxx_associative_heterogeneous_erasure // C++23
+      template<__heterogeneous_hash_key<unordered_map> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       { return _M_extract_tr(__key); }
+#endif
 
       iterator
       insert(node_type&& __nh)
@@ -1495,20 +1521,7 @@ namespace __debug
 
       size_type
       erase(const key_type& __key)
-      {
-       size_type __ret(0);
-       size_type __bucket_count = this->bucket_count();
-       auto __pair = _Base::equal_range(__key);
-       for (auto __victim = __pair.first; __victim != __pair.second;)
-         {
-           _M_invalidate(__victim);
-           __victim = _Base::erase(__victim);
-           ++__ret;
-         }
-
-       _M_check_rehashed(__bucket_count);
-       return __ret;
-      }
+      { return _M_erase_tr(__key); }
 
       iterator
       erase(const_iterator __it)
@@ -1550,6 +1563,13 @@ namespace __debug
        return { __next, this };
       }
 
+#ifdef __glibcxx_associative_heterogeneous_erasure // C++23
+      template<__heterogeneous_hash_key<unordered_multimap> _Kt>
+       size_type
+       erase(_Kt&& __key)
+       { return _M_erase_tr(__key); }
+#endif
+
       using _Base::rehash;
       using _Base::reserve;
 
@@ -1587,7 +1607,35 @@ namespace __debug
        return __next;
       }
 
+      template<typename _Kt>
+       size_type
+       _M_erase_tr(const _Kt& __key)
+       {
+         size_type __ret(0);
+         size_type __bucket_count = this->bucket_count();
+         auto __pair = this->_M_equal_range_tr(__key);
+         for (auto __victim = __pair.first; __victim != __pair.last;)
+           {
+             _M_invalidate(__victim++);
+             ++__ret;
+           }
+
+         _Base::erase(__first, __last);
+         _M_check_rehashed(__bucket_count);
+         return __ret;
+       }
+
 #ifdef __glibcxx_node_extract // >= C++17 && HOSTED
+      template<typename _Kt>
+       node_type
+       _M_extract_tr(const _Kt& __key)
+       {
+         const auto __position = this->_M_find_tr(__key);
+         if (__position != _Base::end())
+           return _M_extract(__position);
+         return {};
+       }
+
       node_type
       _M_extract(_Base_const_iterator __victim)
       {
diff --git a/libstdc++-v3/include/debug/unordered_set 
b/libstdc++-v3/include/debug/unordered_set
index de999a76890..e511d8a6b38 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -461,12 +461,14 @@ namespace __debug
 
       node_type
       extract(const key_type& __key)
-      {
-       const auto __position = _Base::find(__key);
-       if (__position != _Base::end())
-         return _M_extract(__position);
-       return {};
-      }
+      { return _M_extract_tr(__key); }
+
+#ifdef __glibcxx_associative_heterogeneous_erasure // C++23
+      template<__heterogeneous_hash_key<unordered_set> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       { return _M_extract_tr(__key); }
+#endif
 
       insert_return_type
       insert(node_type&& __nh)
@@ -587,16 +589,7 @@ namespace __debug
 
       size_type
       erase(const key_type& __key)
-      {
-       size_type __ret(0);
-       auto __victim = _Base::find(__key);
-       if (__victim != _Base::end())
-         {
-           _M_erase(__victim);
-           __ret = 1;
-         }
-       return __ret;
-      }
+      { return _M_erase_tr(__key); }
 
       iterator
       erase(const_iterator __it)
@@ -638,6 +631,13 @@ namespace __debug
        return { __next, this };
       }
 
+#ifdef __glibcxx_associative_heterogeneous_erasure // C++23
+      template<__heterogeneous_hash_key<unordered_set> _Kt>
+       size_type
+       erase(_Kt&& __key)
+       { return _M_erase_tr(__key); }
+#endif
+
       _Base&
       _M_base() noexcept { return *this; }
 
@@ -662,6 +662,20 @@ namespace __debug
          { return __it == __victim; });
       }
 
+      template<typename _Kt>
+       size_type
+       _M_erase_tr(const _Kt& __key)
+       {
+         size_type __ret(0);
+         auto __victim = this->_M_find_tr(__key);
+         if (__victim != _Base::end())
+           {
+             _M_erase(__victim);
+             __ret = 1;
+           }
+         return __ret;
+       }
+
       _Base_iterator
       _M_erase(_Base_const_iterator __victim)
       {
@@ -673,6 +687,16 @@ namespace __debug
       }
 
 #ifdef __glibcxx_node_extract // >= C++17 && HOSTED
+      template<typename _Kt>
+       node_type
+       _M_extract_tr(const _Kt& __key)
+       {
+         const auto __position = this->_M_find_tr(__key);
+         if (__position != _Base::end())
+           return _M_extract(__position);
+         return {};
+       }
+
       node_type
       _M_extract(_Base_const_iterator __victim)
       {
@@ -1195,12 +1219,14 @@ namespace __debug
 
       node_type
       extract(const key_type& __key)
-      {
-       const auto __position = _Base::find(__key);
-       if (__position != _Base::end())
-         return _M_extract(__position);
-       return {};
-      }
+      { return _M_extract_tr(__key); }
+
+#ifdef __glibcxx_associative_heterogeneous_erasure // C++23
+      template<__heterogeneous_hash_key<unordered_multiset> _Kt>
+       node_type
+       extract(_Kt&& __key)
+       { return _M_extract_tr(__key); }
+#endif
 
       iterator
       insert(node_type&& __nh)
@@ -1317,18 +1343,7 @@ namespace __debug
 
       size_type
       erase(const key_type& __key)
-      {
-       size_type __ret(0);
-       auto __pair = _Base::equal_range(__key);
-       for (auto __victim = __pair.first; __victim != __pair.second;)
-         {
-           _M_invalidate(__victim);
-           __victim = _Base::erase(__victim);
-           ++__ret;
-         }
-
-       return __ret;
-      }
+      { return _M_erase_tr(__key); }
 
       iterator
       erase(const_iterator __it)
@@ -1366,6 +1381,13 @@ namespace __debug
        return { _Base::erase(__first.base(), __last.base()), this };
       }
 
+#ifdef __glibcxx_associative_heterogeneous_erasure // C++23
+      template<__heterogeneous_hash_key<unordered_multiset> _Kt>
+       size_type
+       erase(_Kt&& __key)
+       { return _M_erase_tr(__key); }
+#endif
+
       _Base&
       _M_base() noexcept       { return *this; }
 
@@ -1400,7 +1422,35 @@ namespace __debug
        return __next;
       }
 
+      template<typename _Kt>
+       size_type
+       _M_erase_tr(const _Kt& __key)
+       {
+         size_type __ret(0);
+         size_type __bucket_count = this->bucket_count();
+         auto __pair = this->_M_equal_range_tr(__key);
+         for (auto __victim = __pair.first; __victim != __pair.second;)
+           {
+             _M_invalidate(__victim++);
+             ++__ret;
+           }
+
+         _Base::erase(__pair.first, __pair.second);
+         _M_check_rehash(__bucket_count);
+         return __ret;
+       }
+
 #ifdef __glibcxx_node_extract // >= C++17 && HOSTED
+      template<typename _Kt>
+       node_type
+       _M_extract_tr(const _Kt& __key)
+       {
+         const auto __position = this->_M_find_tr(__key);
+         if (__position != _Base::end())
+           return _M_extract(__position);
+         return {};
+       }
+
       node_type
       _M_extract(_Base_const_iterator __victim)
       {

Reply via email to