[libcxx-commits] [libcxx] [libc++] [containers] P2077R3: Heterogeneous erasure overloads for associative containers (PR #174680)
Rafail Shakhin ogly via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jan 7 06:07:31 PST 2026
https://github.com/rsaddatimov updated https://github.com/llvm/llvm-project/pull/174680
>From fbebc512bccecdd4ed38c44ebc74778188954319 Mon Sep 17 00:00:00 2001
From: rsaddatimov <rafa.saddatimov at gmail.com>
Date: Wed, 7 Jan 2026 05:11:31 +0300
Subject: [PATCH 1/3] Initial commit: start with set & multiset tests
---
libcxx/include/__tree | 23 ++--
libcxx/include/map | 12 +-
libcxx/include/set | 70 +++++++++-
libcxx/include/unordered_map | 36 +++--
libcxx/include/unordered_set | 36 +++--
.../multiset/extract.transparent.pass.cpp | 27 ++++
.../erase.transparent.pass.cpp | 27 ++++
.../set/erase.transparent.pass.cpp | 27 ++++
.../set/extract.transparent.pass.cpp | 27 ++++
.../support/test_transparent_associative.hpp | 124 ++++++++++++++++++
10 files changed, 365 insertions(+), 44 deletions(-)
create mode 100644 libcxx/test/std/containers/associative/multiset/extract.transparent.pass.cpp
create mode 100644 libcxx/test/std/containers/associative/multiset/multiset.erasure/erase.transparent.pass.cpp
create mode 100644 libcxx/test/std/containers/associative/set/erase.transparent.pass.cpp
create mode 100644 libcxx/test/std/containers/associative/set/extract.transparent.pass.cpp
create mode 100644 libcxx/test/support/test_transparent_associative.hpp
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index fbb48f8196964..6dca5e59e8172 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -1188,10 +1188,10 @@ public:
template <class _Comp2>
_LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(__tree<_Tp, _Comp2, _Allocator>& __source);
+ template <class _NodeHandle, class _Key>
+ _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(const _Key&);
template <class _NodeHandle>
- _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(key_type const&);
- template <class _NodeHandle>
- _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(const_iterator);
+ _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract_iterator(const_iterator);
#endif
_LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p);
@@ -1426,7 +1426,8 @@ private:
#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
_LIBCPP_HIDE_FROM_ABI
#endif
- __node_pointer __construct_from_tree(__node_pointer __src, _NodeConstructor __construct) {
+ __node_pointer
+ __construct_from_tree(__node_pointer __src, _NodeConstructor __construct) {
if (!__src)
return nullptr;
@@ -1471,7 +1472,8 @@ private:
#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
_LIBCPP_HIDE_FROM_ABI
#endif
- __node_pointer __assign_from_tree(
+ __node_pointer
+ __assign_from_tree(
__node_pointer __dest, __node_pointer __src, _Assignment __assign, _ConstructionAlg __construct_subtree) {
if (!__src) {
destroy(__dest);
@@ -1943,7 +1945,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(_NodeHandle&& __n
if (__nh.empty())
return _InsertReturnType{end(), false, _NodeHandle()};
- __node_pointer __ptr = __nh.__ptr_;
+ __node_pointer __ptr = __nh.__ptr_;
auto [__parent, __child] = __find_equal(__ptr->__get_value());
if (__child != nullptr)
return _InsertReturnType{iterator(static_cast<__node_pointer>(__child)), false, std::move(__nh)};
@@ -1973,17 +1975,18 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(const_iterator __
}
template <class _Tp, class _Compare, class _Allocator>
-template <class _NodeHandle>
-_LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_extract(key_type const& __key) {
+template <class _NodeHandle, class _Key>
+_LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_extract(const _Key& __key) {
iterator __it = find(__key);
if (__it == end())
return _NodeHandle();
- return __node_handle_extract<_NodeHandle>(__it);
+ return __node_handle_extract_iterator<_NodeHandle>(__it);
}
template <class _Tp, class _Compare, class _Allocator>
template <class _NodeHandle>
-_LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_extract(const_iterator __p) {
+_LIBCPP_HIDE_FROM_ABI _NodeHandle
+__tree<_Tp, _Compare, _Allocator>::__node_handle_extract_iterator(const_iterator __p) {
__node_pointer __np = __p.__get_np();
__remove_node_pointer(__np);
return _NodeHandle(__np, __alloc());
diff --git a/libcxx/include/map b/libcxx/include/map
index 03c92e152e04f..8ad70accd9b47 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -1280,7 +1280,7 @@ public:
return __tree_.template __node_handle_extract<node_type>(__key);
}
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
- return __tree_.template __node_handle_extract<node_type>(__it.__i_);
+ return __tree_.template __node_handle_extract_iterator<node_type>(__it.__i_);
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(map<key_type, mapped_type, _Compare2, allocator_type>& __source) {
@@ -1339,9 +1339,8 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <typename _K2,
- enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>,
- int> = 0>
+ template <typename _K2>
+ requires __is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1880,7 +1879,7 @@ public:
return __tree_.template __node_handle_extract<node_type>(__key);
}
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
- return __tree_.template __node_handle_extract<node_type>(__it.__i_);
+ return __tree_.template __node_handle_extract_iterator<node_type>(__it.__i_);
}
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(multimap<key_type, mapped_type, _Compare2, allocator_type>& __source) {
@@ -1939,7 +1938,8 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
+ template <typename _K2>
+ requires __is_transparent_v<_Compare, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
diff --git a/libcxx/include/set b/libcxx/include/set
index 265c2f6cb6501..c931cf23525fa 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -125,13 +125,19 @@ public:
node_type extract(const_iterator position); // C++17
node_type extract(const key_type& x); // C++17
+ template <typename K>
+ node_type extract(K&& k); // C++23
+
insert_return_type insert(node_type&& nh); // C++17
iterator insert(const_iterator hint, node_type&& nh); // C++17
iterator erase(const_iterator position);
iterator erase(iterator position); // C++14
size_type erase(const key_type& k);
+ template <typename K>
+ size_type erase(K&& k); // C++23
iterator erase(const_iterator first, const_iterator last);
+
void clear() noexcept;
template<class C2>
@@ -370,6 +376,9 @@ public:
node_type extract(const_iterator position); // C++17
node_type extract(const key_type& x); // C++17
+ template <typename K>
+ node_type extract(K&& k); // C++23
+
iterator insert(node_type&& nh); // C++17
iterator insert(const_iterator hint, node_type&& nh); // C++17
@@ -377,6 +386,9 @@ public:
iterator erase(iterator position); // C++14
size_type erase(const key_type& k);
iterator erase(const_iterator first, const_iterator last);
+ template <typename K>
+ size_type erase(K&& k); // C++23
+
void clear() noexcept;
template<class C2>
@@ -770,6 +782,18 @@ public:
_LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p); }
_LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_unique(__k); }
_LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) { return __tree_.erase(__f, __l); }
+
+# if _LIBCPP_STD_VER >= 23
+
+ template <class _Kp>
+ requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> &&
+ !is_convertible_v<_Kp &&, const_iterator>)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type erase(_Kp&& __kp) {
+ return __tree_.__erase_unique(__kp);
+ }
+
+# endif // _LIBCPP_STD_VER >= 23
+
_LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __tree_.clear(); }
# if _LIBCPP_STD_VER >= 17
@@ -787,8 +811,20 @@ public:
return __tree_.template __node_handle_extract<node_type>(__key);
}
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
- return __tree_.template __node_handle_extract<node_type>(__it);
+ return __tree_.template __node_handle_extract_iterator<node_type>(__it);
}
+
+# if _LIBCPP_STD_VER >= 23
+
+ template <class _Kp>
+ requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> &&
+ !is_convertible_v<_Kp &&, const_iterator>)
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 node_type extract(_Kp&& __kp) {
+ return __tree_.template __node_handle_extract<node_type>(__kp);
+ }
+
+# endif // _LIBCPP_STD_VER >= 23
+
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(set<key_type, _Compare2, allocator_type>& __source) {
_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
@@ -847,7 +883,8 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
+ template <typename _K2>
+ requires __is_transparent_v<_Compare, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1245,6 +1282,18 @@ public:
_LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p); }
_LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_multi(__k); }
_LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) { return __tree_.erase(__f, __l); }
+
+# if _LIBCPP_STD_VER >= 23
+
+ template <class _Kp>
+ requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> &&
+ !is_convertible_v<_Kp &&, const_iterator>)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type erase(_Kp&& __kp) {
+ return __tree_.__erase_multi(__kp);
+ }
+
+# endif // _LIBCPP_STD_VER >= 23
+
_LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __tree_.clear(); }
# if _LIBCPP_STD_VER >= 17
@@ -1262,8 +1311,20 @@ public:
return __tree_.template __node_handle_extract<node_type>(__key);
}
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
- return __tree_.template __node_handle_extract<node_type>(__it);
+ return __tree_.template __node_handle_extract_iterator<node_type>(__it);
}
+
+# if _LIBCPP_STD_VER >= 23
+
+ template <class _Kp>
+ requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> &&
+ !is_convertible_v<_Kp &&, const_iterator>)
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 node_type extract(_Kp&& __kp) {
+ return __tree_.template __node_handle_extract<node_type>(__kp);
+ }
+
+# endif // _LIBCPP_STD_VER >= 23
+
template <class _Compare2>
_LIBCPP_HIDE_FROM_ABI void merge(multiset<key_type, _Compare2, allocator_type>& __source) {
_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
@@ -1324,7 +1385,8 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
+ template <typename _K2>
+ requires __is_transparent_v<_Compare, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index ca53348eb5e2a..4de5ea87a19cb 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -1216,11 +1216,13 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
@@ -1230,7 +1232,8 @@ public:
return __table_.__count_unique(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_unique(__k);
}
@@ -1239,7 +1242,8 @@ public:
# if _LIBCPP_STD_VER >= 20
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1252,11 +1256,13 @@ public:
return __table_.__equal_range_unique(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_unique(__k);
}
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_unique(__k);
}
@@ -1936,11 +1942,13 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
@@ -1950,7 +1958,8 @@ public:
return __table_.__count_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_multi(__k);
}
@@ -1959,7 +1968,8 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1972,11 +1982,13 @@ public:
return __table_.__equal_range_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_multi(__k);
}
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_multi(__k);
}
diff --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index 760f145091895..442c9ce26361f 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -844,11 +844,13 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
@@ -858,7 +860,8 @@ public:
return __table_.__count_unique(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_unique(__k);
}
@@ -867,7 +870,8 @@ public:
# if _LIBCPP_STD_VER >= 20
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -880,11 +884,13 @@ public:
return __table_.__equal_range_unique(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_unique(__k);
}
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_unique(__k);
}
@@ -1443,11 +1449,13 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
@@ -1457,7 +1465,8 @@ public:
return __table_.__count_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_multi(__k);
}
@@ -1466,7 +1475,8 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1479,11 +1489,13 @@ public:
return __table_.__equal_range_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_multi(__k);
}
- template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
+ template <class _K2>
+ requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_multi(__k);
}
diff --git a/libcxx/test/std/containers/associative/multiset/extract.transparent.pass.cpp b/libcxx/test/std/containers/associative/multiset/extract.transparent.pass.cpp
new file mode 100644
index 0000000000000..fc04c8d85c267
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/extract.transparent.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <set>
+
+// class multiset
+
+// template<typename K>
+// node_type extract(K&& k) const; // C++23
+
+#include <set>
+#include "test_transparent_associative.hpp"
+
+int main(int, char**) {
+ test_transparent_extract<std::multiset<StoredType<int>, transparent_comparator_base>>({1, 2, 4});
+
+ test_transparent_extract<std::multiset<StoredType<int>, transparent_comparator_final>>({1, 2, 4});
+
+ test_non_transparent_extract<std::multiset<StoredType<int>, std::less<StoredType<int>>>>({1, 2});
+}
diff --git a/libcxx/test/std/containers/associative/multiset/multiset.erasure/erase.transparent.pass.cpp b/libcxx/test/std/containers/associative/multiset/multiset.erasure/erase.transparent.pass.cpp
new file mode 100644
index 0000000000000..a7252f0aa039c
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/multiset.erasure/erase.transparent.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <set>
+
+// class multiset
+
+// template<typename K>
+// size_type erase(K&& k) const; // C++23
+
+#include <set>
+#include "test_transparent_associative.hpp"
+
+int main(int, char**) {
+ test_transparent_erase<std::multiset<StoredType<int>, transparent_comparator_base>>({1, 2, 4, 5});
+
+ test_transparent_erase<std::multiset<StoredType<int>, transparent_comparator_final>>({1, 2, 4, 5});
+
+ test_non_transparent_erase<std::multiset<StoredType<int>, std::less<StoredType<int>>>>({1, 2});
+}
diff --git a/libcxx/test/std/containers/associative/set/erase.transparent.pass.cpp b/libcxx/test/std/containers/associative/set/erase.transparent.pass.cpp
new file mode 100644
index 0000000000000..d2ca1fe599374
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/erase.transparent.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <set>
+
+// class set
+
+// template<typename K>
+// size_type erase(K&& k) const; // C++23
+
+#include <set>
+#include "test_transparent_associative.hpp"
+
+int main(int, char**) {
+ test_transparent_erase<std::set<StoredType<int>, transparent_comparator_base>>({1, 2, 4, 5});
+
+ test_transparent_erase<std::set<StoredType<int>, transparent_comparator_final>>({1, 2, 4, 5});
+
+ test_non_transparent_erase<std::set<StoredType<int>, std::less<StoredType<int>>>>({1, 2});
+}
diff --git a/libcxx/test/std/containers/associative/set/extract.transparent.pass.cpp b/libcxx/test/std/containers/associative/set/extract.transparent.pass.cpp
new file mode 100644
index 0000000000000..62c72808b83d1
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/extract.transparent.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <set>
+
+// class set
+
+// template<typename K>
+// node_type extract(K&& k) const; // C++23
+
+#include <set>
+#include "test_transparent_associative.hpp"
+
+int main(int, char**) {
+ test_transparent_extract<std::set<StoredType<int>, transparent_comparator_base>>({1, 2, 4});
+
+ test_transparent_extract<std::set<StoredType<int>, transparent_comparator_final>>({1, 2, 4});
+
+ test_non_transparent_extract<std::set<StoredType<int>, std::less<StoredType<int>>>>({1, 2});
+}
diff --git a/libcxx/test/support/test_transparent_associative.hpp b/libcxx/test/support/test_transparent_associative.hpp
new file mode 100644
index 0000000000000..a59f10e426ecc
--- /dev/null
+++ b/libcxx/test/support/test_transparent_associative.hpp
@@ -0,0 +1,124 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_TRANSPARENT_ASSOCIATIVE_H
+#define TEST_TRANSPARENT_ASSOCIATIVE_H
+
+#include "test_macros.h"
+
+#include <cassert>
+
+#if TEST_STD_VER > 23
+
+template <typename T>
+struct StoredType;
+
+template <typename T>
+struct SearchedType {
+ explicit SearchedType(T value, int* counter) : value_(value), conversions_(counter) {}
+
+ operator StoredType<T>() const {
+ ++*conversions_;
+ return StoredType<T>{value_};
+ }
+
+ T get_value() const { return value_; }
+
+ auto operator<=>(const SearchedType<T>&) const = default;
+
+private:
+ T value_;
+ int* conversions_;
+};
+
+template <typename T>
+struct StoredType {
+ StoredType() = default;
+ StoredType(T value) : value_(value) {}
+
+ T get_value() const { return value_; }
+
+ auto operator<=>(const StoredType<T>&) const = default;
+
+private:
+ T value_;
+};
+
+struct transparent_comparator_base {
+ using is_transparent = void;
+
+ template <typename T>
+ bool operator()(const SearchedType<T>& lhs, const StoredType<T>& rhs) const {
+ return lhs.get_value() < rhs.get_value();
+ }
+
+ template <typename T>
+ bool operator()(const StoredType<T>& lhs, const SearchedType<T>& rhs) const {
+ return lhs.get_value() < rhs.get_value();
+ }
+
+ template <typename T>
+ bool operator()(const StoredType<T>& lhs, const StoredType<T>& rhs) const {
+ return lhs < rhs;
+ }
+};
+
+struct transparent_comparator_final final : public transparent_comparator_base {};
+
+template <class Container>
+void test_transparent_erase(Container c) {
+ int conversions = 0;
+ assert(c.erase(SearchedType<int>(1, &conversions)) != 0);
+ assert(c.erase(SearchedType<int>(2, &conversions)) != 0);
+ assert(c.erase(SearchedType<int>(3, &conversions)) == 0);
+
+ assert(conversions == 0);
+
+ c.erase(c.begin());
+ c.erase(c.cbegin());
+
+ assert(c.empty());
+}
+
+template <class Container>
+void test_non_transparent_erase(Container c) {
+ int conversions = 0;
+ assert(c.erase(SearchedType<int>(1, &conversions)) != 0);
+ assert(conversions == 1);
+ assert(c.erase(SearchedType<int>(2, &conversions)) != 0);
+ assert(conversions == 2);
+ assert(c.erase(SearchedType<int>(3, &conversions)) == 0);
+ assert(conversions == 3);
+}
+
+template <class Container>
+void test_transparent_extract(Container c) {
+ int conversions = 0;
+ assert(!c.extract(SearchedType<int>(1, &conversions)).empty());
+ assert(!c.extract(SearchedType<int>(2, &conversions)).empty());
+ assert(c.extract(SearchedType<int>(3, &conversions)).empty());
+ assert(conversions == 0);
+
+ assert(!c.extract(c.cbegin()).empty());
+ assert(c.empty());
+}
+
+template <class Container>
+void test_non_transparent_extract(Container c) {
+ int conversions = 0;
+ assert(!c.extract(SearchedType<int>(1, &conversions)).empty());
+ assert(conversions == 1);
+ assert(!c.extract(SearchedType<int>(2, &conversions)).empty());
+ assert(conversions == 2);
+ assert(c.extract(SearchedType<int>(3, &conversions)).empty());
+ assert(conversions == 3);
+}
+
+#endif // TEST_STD_VER > 23
+
+#endif // TEST_TRANSPARENT_ASSOCIATIVE_H
>From 30e0b8e54141fac012aaa2d8091609adc62b9fac Mon Sep 17 00:00:00 2001
From: rsaddatimov <rafa.saddatimov at gmail.com>
Date: Wed, 7 Jan 2026 06:22:38 +0300
Subject: [PATCH 2/3] Fix test & version stuff
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +-
libcxx/docs/ReleaseNotes/22.rst | 1 +
libcxx/docs/Status/Cxx23Papers.csv | 2 +-
libcxx/include/__tree | 6 ++--
libcxx/include/version | 2 +-
.../map.version.compile.pass.cpp | 32 ++++++-------------
.../set.version.compile.pass.cpp | 32 ++++++-------------
.../unordered_map.version.compile.pass.cpp | 32 ++++++-------------
.../unordered_set.version.compile.pass.cpp | 32 ++++++-------------
.../version.version.compile.pass.cpp | 32 ++++++-------------
.../support/test_transparent_associative.hpp | 4 +--
.../generate_feature_test_macro_components.py | 1 -
12 files changed, 58 insertions(+), 120 deletions(-)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 32911d0f64449..9beb5b511b5bb 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -314,7 +314,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_allocate_at_least`` ``202302L``
---------------------------------------------------------- -----------------
- ``__cpp_lib_associative_heterogeneous_erasure`` *unimplemented*
+ ``__cpp_lib_associative_heterogeneous_erasure`` ``202110L``
---------------------------------------------------------- -----------------
``__cpp_lib_bind_back`` ``202202L``
---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 3e2b3e6633bb1..f9313a6f5907b 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -38,6 +38,7 @@ What's New in Libc++ 22.0.0?
Implemented Papers
------------------
+- P2077R3: Heterogeneous erasure overloads for associative containers (`Github <https://llvm.org/PR105165>`__)
- P2592R3: Hashing support for ``std::chrono`` value classes (`Github <https://llvm.org/PR105358>`__)
- P2321R2: ``zip`` (`Github <https://llvm.org/PR105169>`__) (The paper is partially implemented. ``zip_transform_view``,
``adjacent_view``, and ``adjacent_transform_view`` are implemented in this release)
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index e4c6cb0f51065..842bfb713a390 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -30,7 +30,7 @@
"`P1147R1 <https://wg21.link/P1147R1>`__","Printing ``volatile`` Pointers","2021-10 (Virtual)","|Complete|","14","`#105161 <https://github.com/llvm/llvm-project/issues/105161>`__",""
"`P1272R4 <https://wg21.link/P1272R4>`__","Byteswapping for fun&&nuf","2021-10 (Virtual)","|Complete|","14","`#105163 <https://github.com/llvm/llvm-project/issues/105163>`__",""
"`P1675R2 <https://wg21.link/P1675R2>`__","``rethrow_exception`` must be allowed to copy","2021-10 (Virtual)","|Nothing To Do|","","`#105164 <https://github.com/llvm/llvm-project/issues/105164>`__",""
-"`P2077R3 <https://wg21.link/P2077R3>`__","Heterogeneous erasure overloads for associative containers","2021-10 (Virtual)","","","`#105165 <https://github.com/llvm/llvm-project/issues/105165>`__",""
+"`P2077R3 <https://wg21.link/P2077R3>`__","Heterogeneous erasure overloads for associative containers","2021-10 (Virtual)","Complete","22","`#105165 <https://github.com/llvm/llvm-project/issues/105165>`__",""
"`P2251R1 <https://wg21.link/P2251R1>`__","Require ``span`` & ``basic_string_view`` to be Trivially Copyable","2021-10 (Virtual)","|Complete|","14","`#105166 <https://github.com/llvm/llvm-project/issues/105166>`__",""
"`P2301R1 <https://wg21.link/P2301R1>`__","Add a ``pmr`` alias for ``std::stacktrace``","2021-10 (Virtual)","","","`#105167 <https://github.com/llvm/llvm-project/issues/105167>`__",""
"`P2321R2 <https://wg21.link/P2321R2>`__","``zip``","2021-10 (Virtual)","|In Progress|","","`#105169 <https://github.com/llvm/llvm-project/issues/105169>`__",""
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index 6dca5e59e8172..8a12e75033d20 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -1426,8 +1426,7 @@ private:
#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
_LIBCPP_HIDE_FROM_ABI
#endif
- __node_pointer
- __construct_from_tree(__node_pointer __src, _NodeConstructor __construct) {
+ __node_pointer __construct_from_tree(__node_pointer __src, _NodeConstructor __construct) {
if (!__src)
return nullptr;
@@ -1472,8 +1471,7 @@ private:
#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
_LIBCPP_HIDE_FROM_ABI
#endif
- __node_pointer
- __assign_from_tree(
+ __node_pointer __assign_from_tree(
__node_pointer __dest, __node_pointer __src, _Assignment __assign, _ConstructionAlg __construct_subtree) {
if (!__src) {
destroy(__dest);
diff --git a/libcxx/include/version b/libcxx/include/version
index 1d2422e64ba0f..7ea4f43b068cb 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -486,7 +486,7 @@ __cpp_lib_void_t 201411L <type_traits>
#if _LIBCPP_STD_VER >= 23
# define __cpp_lib_adaptor_iterator_pair_constructor 202106L
# define __cpp_lib_allocate_at_least 202302L
-// # define __cpp_lib_associative_heterogeneous_erasure 202110L
+# define __cpp_lib_associative_heterogeneous_erasure 202110L
# define __cpp_lib_bind_back 202202L
# define __cpp_lib_byteswap 202110L
# define __cpp_lib_constexpr_bitset 202207L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.compile.pass.cpp
index 3db3861c72b5c..806aba542b7e9 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.compile.pass.cpp
@@ -231,17 +231,11 @@
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++23"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
# endif
# ifdef __cpp_lib_associative_heterogeneous_insertion
@@ -312,17 +306,11 @@
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.compile.pass.cpp
index 5dc69f29d0ecd..abc32dad7e7c9 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.compile.pass.cpp
@@ -193,17 +193,11 @@
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++23"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
# endif
# ifdef __cpp_lib_associative_heterogeneous_insertion
@@ -254,17 +248,11 @@
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.compile.pass.cpp
index 221d8aaebc14b..ba777e5434008 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.compile.pass.cpp
@@ -225,17 +225,11 @@
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++23"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
# endif
# ifdef __cpp_lib_associative_heterogeneous_insertion
@@ -306,17 +300,11 @@
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.compile.pass.cpp
index d1c1335df7c80..b168215ea737b 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.compile.pass.cpp
@@ -187,17 +187,11 @@
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++23"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
# endif
# ifdef __cpp_lib_associative_heterogeneous_insertion
@@ -248,17 +242,11 @@
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index d54e229a87fcb..00ce5753208ae 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -4600,17 +4600,11 @@
# error "__cpp_lib_as_const should have the value 201510L in c++23"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++23"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++23"
# endif
# ifdef __cpp_lib_associative_heterogeneous_insertion
@@ -6270,17 +6264,11 @@
# error "__cpp_lib_as_const should have the value 201510L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
-# endif
-# if __cpp_lib_associative_heterogeneous_erasure != 202110L
-# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
-# endif
-# else
-# ifdef __cpp_lib_associative_heterogeneous_erasure
-# error "__cpp_lib_associative_heterogeneous_erasure should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_associative_heterogeneous_erasure
+# error "__cpp_lib_associative_heterogeneous_erasure should be defined in c++26"
+# endif
+# if __cpp_lib_associative_heterogeneous_erasure != 202110L
+# error "__cpp_lib_associative_heterogeneous_erasure should have the value 202110L in c++26"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/support/test_transparent_associative.hpp b/libcxx/test/support/test_transparent_associative.hpp
index a59f10e426ecc..6ec13d29000ea 100644
--- a/libcxx/test/support/test_transparent_associative.hpp
+++ b/libcxx/test/support/test_transparent_associative.hpp
@@ -13,7 +13,7 @@
#include <cassert>
-#if TEST_STD_VER > 23
+#if TEST_STD_VER >= 23
template <typename T>
struct StoredType;
@@ -119,6 +119,6 @@ void test_non_transparent_extract(Container c) {
assert(conversions == 3);
}
-#endif // TEST_STD_VER > 23
+#endif // TEST_STD_VER >= 23
#endif // TEST_TRANSPARENT_ASSOCIATIVE_H
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 370bc5d26b535..213e5815a36a0 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -152,7 +152,6 @@ def add_version_header(tc):
"name": "__cpp_lib_associative_heterogeneous_erasure",
"values": {"c++23": 202110},
"headers": ["map", "set", "unordered_map", "unordered_set"],
- "unimplemented": True,
},
{
"name": "__cpp_lib_associative_heterogeneous_insertion",
>From 45c19e49f53328752bfdf079577cc79f33898551 Mon Sep 17 00:00:00 2001
From: rsaddatimov <rafa.saddatimov at gmail.com>
Date: Wed, 7 Jan 2026 17:07:16 +0300
Subject: [PATCH 3/3] Back to sfinae
---
libcxx/include/map | 8 ++++----
libcxx/include/set | 6 ++----
libcxx/include/unordered_map | 36 ++++++++++++------------------------
libcxx/include/unordered_set | 36 ++++++++++++------------------------
4 files changed, 30 insertions(+), 56 deletions(-)
diff --git a/libcxx/include/map b/libcxx/include/map
index 8ad70accd9b47..dc40a652fad74 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -1339,8 +1339,9 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <typename _K2>
- requires __is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>
+ template <typename _K2,
+ enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>,
+ int> = 0>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1938,8 +1939,7 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <typename _K2>
- requires __is_transparent_v<_Compare, _K2>
+ template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
diff --git a/libcxx/include/set b/libcxx/include/set
index c931cf23525fa..7854d585b6a19 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -883,8 +883,7 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <typename _K2>
- requires __is_transparent_v<_Compare, _K2>
+ template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1385,8 +1384,7 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <typename _K2>
- requires __is_transparent_v<_Compare, _K2>
+ template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index 4de5ea87a19cb..ca53348eb5e2a 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -1216,13 +1216,11 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
@@ -1232,8 +1230,7 @@ public:
return __table_.__count_unique(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_unique(__k);
}
@@ -1242,8 +1239,7 @@ public:
# if _LIBCPP_STD_VER >= 20
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1256,13 +1252,11 @@ public:
return __table_.__equal_range_unique(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_unique(__k);
}
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_unique(__k);
}
@@ -1942,13 +1936,11 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
@@ -1958,8 +1950,7 @@ public:
return __table_.__count_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_multi(__k);
}
@@ -1968,8 +1959,7 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1982,13 +1972,11 @@ public:
return __table_.__equal_range_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_multi(__k);
}
- template <class _K2>
- requires __is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_multi(__k);
}
diff --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index 442c9ce26361f..760f145091895 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -844,13 +844,11 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
@@ -860,8 +858,7 @@ public:
return __table_.__count_unique(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_unique(__k);
}
@@ -870,8 +867,7 @@ public:
# if _LIBCPP_STD_VER >= 20
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -884,13 +880,11 @@ public:
return __table_.__equal_range_unique(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_unique(__k);
}
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_unique(__k);
}
@@ -1449,13 +1443,11 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); }
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) {
return __table_.find(__k);
}
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const {
return __table_.find(__k);
}
@@ -1465,8 +1457,7 @@ public:
return __table_.__count_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const {
return __table_.__count_multi(__k);
}
@@ -1475,8 +1466,7 @@ public:
# if _LIBCPP_STD_VER >= 20
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); }
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const {
return find(__k) != end();
}
@@ -1489,13 +1479,11 @@ public:
return __table_.__equal_range_multi(__k);
}
# if _LIBCPP_STD_VER >= 20
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) {
return __table_.__equal_range_multi(__k);
}
- template <class _K2>
- requires __is_transparent_v<hasher> && __is_transparent_v<key_equal>
+ template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const {
return __table_.__equal_range_multi(__k);
}
More information about the libcxx-commits
mailing list