On Thu, 12 Feb 2026 at 18:12, Nathan Myers <[email protected]> wrote:
>
> Changes in v2:
> - Fix numerous errors revealed by actual testing.
> - Delete excess overloads in unordered_multimap and
> unordered_multiset.
>
> Implement the debug versions of new overloads from P2363.
>
> Also, simplify implementation of other overloads to match.
>
> libstdc++-v3/ChangeLog:
> PR libstdc++/117402
> * include/debug/map.h (try_emplace (2x), insert_or_assign (2x)):
> Define heterogeneous overloads, simplify existing overloads.
> * include/debug/unordered_map: Same.
> * include/debug/set.h (insert (2x)):
> Define heterogeneous overloads.
> * include/debug/unordered_set: Same.
> ---
> libstdc++-v3/include/debug/map.h | 83 +++++++++++++++++-------
> libstdc++-v3/include/debug/set.h | 21 ++++++
> libstdc++-v3/include/debug/unordered_map | 64 +++++++++++++++---
> libstdc++-v3/include/debug/unordered_set | 26 ++++++++
> 4 files changed, 161 insertions(+), 33 deletions(-)
>
> diff --git a/libstdc++-v3/include/debug/map.h
> b/libstdc++-v3/include/debug/map.h
> index 0fc7afae385..d6d2600d904 100644
> --- a/libstdc++-v3/include/debug/map.h
> +++ b/libstdc++-v3/include/debug/map.h
> @@ -382,18 +382,26 @@ namespace __debug
> return { { __res.first, this }, __res.second };
> }
>
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_tree_key<map> _Kt, typename... _Args>
> + pair<iterator, bool>
> + try_emplace(_Kt&& __k, _Args&&... __args)
> + {
> + auto __res = _Base::try_emplace(
> + std::forward<_Kt>(__k), std::forward<_Args>(__args)...);
> + return { { __res.first, this }, __res.second };
> + }
> +#endif
> +
> template <typename... _Args>
> iterator
> try_emplace(const_iterator __hint, const key_type& __k,
> _Args&&... __args)
> {
> __glibcxx_check_insert(__hint);
> - return
> - {
> - _Base::try_emplace(__hint.base(), __k,
> - std::forward<_Args>(__args)...),
> - this
> - };
> + auto __it = _Base::try_emplace(__hint.base(), __k,
> + std::forward<_Args>(__args)...);
> + return { __it, this };
> }
>
> template <typename... _Args>
> @@ -401,14 +409,23 @@ namespace __debug
> try_emplace(const_iterator __hint, key_type&& __k, _Args&&... __args)
> {
> __glibcxx_check_insert(__hint);
> - return
> - {
> - _Base::try_emplace(__hint.base(), std::move(__k),
> - std::forward<_Args>(__args)...),
> - this
> - };
> + auto __it = _Base::try_emplace(__hint.base(), std::move(__k),
> + std::forward<_Args>(__args)...);
> + return { __it, this };
> }
>
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_tree_key<map> _Kt, typename... _Args>
> + iterator
> + try_emplace(const_iterator __hint, _Kt&& __k, _Args&&... __args)
> + {
> + __glibcxx_check_insert(__hint);
> + auto __it = _Base::try_emplace(__hint.base(),
> + std::forward<_Kt>(__k), std::forward<_Args>(__args)...);
> + return { __it, this };
> + }
> +# endif
> +
> template <typename _Obj>
> std::pair<iterator, bool>
> insert_or_assign(const key_type& __k, _Obj&& __obj)
> @@ -427,18 +444,26 @@ namespace __debug
> return { { __res.first, this }, __res.second };
> }
>
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_tree_key<map> _Kt, typename _Obj>
> + std::pair<iterator, bool>
> + insert_or_assign(_Kt&& __k, _Obj&& __obj)
> + {
> + auto __res = _Base::insert_or_assign(
> + std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
> + return { { __res.first, this }, __res.second };
> + }
> +#endif
> +
> template <typename _Obj>
> iterator
> insert_or_assign(const_iterator __hint,
> const key_type& __k, _Obj&& __obj)
> {
> __glibcxx_check_insert(__hint);
> - return
> - {
> - _Base::insert_or_assign(__hint.base(), __k,
> - std::forward<_Obj>(__obj)),
> - this
> - };
> + auto __it = _Base::insert_or_assign(__hint.base(), __k,
> + std::forward<_Obj>(__obj));
> + return { __it, this };
> }
>
> template <typename _Obj>
> @@ -446,13 +471,23 @@ namespace __debug
> insert_or_assign(const_iterator __hint, key_type&& __k, _Obj&& __obj)
> {
> __glibcxx_check_insert(__hint);
> - return
> - {
> - _Base::insert_or_assign(__hint.base(), std::move(__k),
> - std::forward<_Obj>(__obj)),
> - this
> - };
> + auto __it = _Base::insert_or_assign(__hint.base(), std::move(__k),
> + std::forward<_Obj>(__obj));
> + return { __it, this };
> }
> +
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_tree_key<map> _Kt, typename _Obj>
> + iterator
> + insert_or_assign(const_iterator __hint, _Kt&& __k, _Obj&& __obj)
> + {
> + __glibcxx_check_insert(__hint);
> + auto __it = _Base::insert_or_assign(__hint.base(),
> + std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
> + return { __it, this };
> + }
> +# endif
> +
> #endif // C++17
>
> #ifdef __glibcxx_node_extract // >= C++17 && HOSTED
> diff --git a/libstdc++-v3/include/debug/set.h
> b/libstdc++-v3/include/debug/set.h
> index 99701d4a6d7..9180a87285b 100644
> --- a/libstdc++-v3/include/debug/set.h
> +++ b/libstdc++-v3/include/debug/set.h
> @@ -283,6 +283,16 @@ namespace __debug
> }
> #endif
>
> +#ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_tree_key<set> _Kt>
> + std::pair<iterator, bool>
> + insert(_Kt&& __x)
> + {
> + auto __res = _Base::insert(std::forward<_Kt>(__x));
> + return { { __res.first, this }, __res.second };
> + }
> +#endif
> +
> iterator
> insert(const_iterator __position, const value_type& __x)
> {
> @@ -299,6 +309,17 @@ namespace __debug
> }
> #endif
>
> +#ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_tree_key<set> _Kt>
> + iterator
> + insert(const_iterator __position, _Kt&& __x)
> + {
> + __glibcxx_check_insert(__position);
> + auto __it = _Base::insert(__position.base(),
> std::forward<_Kt>(__x));
> + return { __it, this };
> + }
> +#endif
> +
> template <typename _InputIterator>
> void
> insert(_InputIterator __first, _InputIterator __last)
> diff --git a/libstdc++-v3/include/debug/unordered_map
> b/libstdc++-v3/include/debug/unordered_map
> index 4bde18c917b..1dda76dcf32 100644
> --- a/libstdc++-v3/include/debug/unordered_map
> +++ b/libstdc++-v3/include/debug/unordered_map
> @@ -500,6 +500,17 @@ namespace __debug
> return { { __res.first, this }, __res.second };
> }
>
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_hash_key<unordered_map> _Kt, typename...
> _Args>
> + pair<iterator, bool>
> + try_emplace(_Kt&& __k, _Args&&... __args)
> + {
> + auto __res = _Base::try_emplace(std::forward<_Kt>(__k),
> + std::forward<_Args>(__args)...);
> + return { { __res.first, this }, __res.second };
> + }
> +# endif
> +
> template <typename... _Args>
> iterator
> try_emplace(const_iterator __hint, const key_type& __k,
> @@ -516,10 +527,21 @@ namespace __debug
> try_emplace(const_iterator __hint, key_type&& __k, _Args&&... __args)
> {
> __glibcxx_check_insert(__hint);
> - return { _Base::try_emplace(__hint.base(), std::move(__k),
> - std::forward<_Args>(__args)...),
> - this };
> + auto __it = _Base::try_emplace(__hint.base(), std::move(__k),
> + std::forward<_Args>(__args)...);
> + return { __it, this };
Are all these try_emplace overloads missing calls to _M_check_rehashed?
I think I should have added those in r6-2989-g66c182be120bb3 when
adding try_emplace to the debug maps.
But that's a pre-existing problem that can be solved separately.
This is OK for trunk (after the main P2363 patch is pushed, of course).
> }
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_hash_key<unordered_map> _Kt, typename...
> _Args>
> + iterator
> + try_emplace(const_iterator __hint, _Kt&& __k, _Args&&... __args)
> + {
> + __glibcxx_check_insert(__hint);
> + auto __it = _Base::try_emplace(__hint.base(),
> + std::forward<_Kt>(__k), std::forward<_Args>(__args)...);
> + return { __it, this };
> + }
> +# endif
>
> template <typename _Obj>
> pair<iterator, bool>
> @@ -539,15 +561,26 @@ namespace __debug
> return { { __res.first, this }, __res.second };
> }
>
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_hash_key<unordered_map> _Kt, typename _Obj>
> + pair<iterator, bool>
> + insert_or_assign(_Kt&& __k, _Obj&& __obj)
> + {
> + auto __res = _Base::insert_or_assign(
> + std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
> + return { { __res.first, this }, __res.second };
> + }
> +# endif
> +
> template <typename _Obj>
> iterator
> insert_or_assign(const_iterator __hint, const key_type& __k,
> _Obj&& __obj)
> {
> __glibcxx_check_insert(__hint);
> - return { _Base::insert_or_assign(__hint.base(), __k,
> - std::forward<_Obj>(__obj)),
> - this };
> + auto __it = _Base::insert_or_assign(__hint.base(), __k,
> + std::forward<_Obj>(__obj));
> + return { __it, this };
> }
>
> template <typename _Obj>
> @@ -555,10 +588,23 @@ namespace __debug
> insert_or_assign(const_iterator __hint, key_type&& __k, _Obj&& __obj)
> {
> __glibcxx_check_insert(__hint);
> - return { _Base::insert_or_assign(__hint.base(), std::move(__k),
> - std::forward<_Obj>(__obj)),
> - this };
> + auto __it = _Base::insert_or_assign(__hint.base(), std::move(__k),
> + std::forward<_Obj>(__obj));
> + return { __it, this };
> }
> +
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_hash_key<unordered_map> _Kt, typename _Obj>
> + iterator
> + insert_or_assign(const_iterator __hint, _Kt&& __k, _Obj&& __obj)
> + {
> + __glibcxx_check_insert(__hint);
> + auto __it = _Base::insert_or_assign(__hint.base(),
> + std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
> + return { __it, this };
> + }
> +# endif
> +
> #endif // C++17
>
> #ifdef __glibcxx_node_extract // >= C++17 && HOSTED
> diff --git a/libstdc++-v3/include/debug/unordered_set
> b/libstdc++-v3/include/debug/unordered_set
> index de999a76890..06430e7cf64 100644
> --- a/libstdc++-v3/include/debug/unordered_set
> +++ b/libstdc++-v3/include/debug/unordered_set
> @@ -413,6 +413,18 @@ namespace __debug
> return { { __res.first, this }, __res.second };
> }
>
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_hash_key<unordered_set> _Kt>
> + std::pair<iterator, bool>
> + insert(_Kt&& __obj)
> + {
> + size_type __bucket_count = this->bucket_count();
> + auto __res = _Base::insert(std::forward<_Kt>(__obj));
> + _M_check_rehashed(__bucket_count);
> + return { { __res.first, this }, __res.second };
> + }
> +#endif
> +
> iterator
> insert(const_iterator __hint, value_type&& __obj)
> {
> @@ -423,6 +435,20 @@ namespace __debug
> return { __it, this };
> }
>
> +# ifdef __glibcxx_associative_heterogeneous_insertion
> + template <__heterogeneous_hash_key<unordered_set> _Kt>
> + iterator
> + insert(const_iterator __hint, _Kt&& __obj)
> + {
> + __glibcxx_check_insert(__hint);
> + size_type __bucket_count = this->bucket_count();
> + auto __it = _Base::insert(
> + __hint.base(), std::forward<_Kt>(__obj));
> + _M_check_rehashed(__bucket_count);
> + return { __it, this };
> + }
> +#endif
> +
> void
> insert(std::initializer_list<value_type> __l)
> {
> --
> 2.52.0
>