On Wed, 19 Mar 2025 at 12:06, Tomasz Kamiński <tkami...@redhat.com> wrote: > > This patch implements part of LWG2713 covering the from_range > constructors, which makes std::ranges::to<std::unordered_set>(alloc) > well-formed. > Likewise for rest of unordered containers. > > As this consturctors were added to v15, this has no impact > on code that compiled with previous versions. > > libstdc++-v3/ChangeLog: > > * include/bits/unordered_map.h > (unordered_map(from_range_t, _Rg&&, const allocator_type&)) > (unordered_multimap(from_range_t, _Rg&&, const allocator_type&)): > Define. > * include/bits/unordered_set.h > (unordered_set(from_range_t, _Rg&&, const allocator_type&)) > (unordered_multiset(from_range_t, _Rg&&, const allocator_type&)): > Define. > * testsuite/23_containers/unordered_map/cons/from_range.cc: New tests. > New tests. > * testsuite/23_containers/unordered_multimap/cons/from_range.cc: > New tests. > * testsuite/23_containers/unordered_multiset/cons/from_range.cc: > New tests. > * testsuite/23_containers/unordered_set/cons/from_range.cc: New tests. > * testsuite/std/ranges/conv/1.cc: New tests. > --- > Testing on x86_64-linux, *unordered_*map* tests passed. > OK for trunk once all tests passes?
OK, thanks. > > libstdc++-v3/include/bits/unordered_map.h | 14 +++++++++++ > libstdc++-v3/include/bits/unordered_set.h | 15 ++++++++++++ > .../unordered_map/cons/from_range.cc | 24 +++++++++---------- > .../unordered_multimap/cons/from_range.cc | 24 +++++++++---------- > .../unordered_multiset/cons/from_range.cc | 22 ++++++++--------- > .../unordered_set/cons/from_range.cc | 9 ++++--- > libstdc++-v3/testsuite/std/ranges/conv/1.cc | 22 +++++++++++++++++ > 7 files changed, 87 insertions(+), 43 deletions(-) > > diff --git a/libstdc++-v3/include/bits/unordered_map.h > b/libstdc++-v3/include/bits/unordered_map.h > index 5c930487190..5e11e61dfc1 100644 > --- a/libstdc++-v3/include/bits/unordered_map.h > +++ b/libstdc++-v3/include/bits/unordered_map.h > @@ -300,6 +300,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER > : _M_h(__n, __hf, __eql, __a) > { insert_range(std::forward<_Rg>(__rg)); } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 2713. More missing allocator-extended constructors for unordered > containers > + template<__detail::__container_compatible_range<value_type> _Rg> > + unordered_map(from_range_t, _Rg&& __rg, const allocator_type& __a) > + : _M_h(0, hasher(), key_equal(), __a) > + { insert_range(std::forward<_Rg>(__rg)); } > + > template<__detail::__container_compatible_range<value_type> _Rg> > unordered_map(from_range_t, _Rg&& __rg, size_type __n, > const allocator_type& __a) > @@ -1546,6 +1553,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER > : _M_h(__n, __hf, __eql, __a) > { insert_range(std::forward<_Rg>(__rg)); } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 2713. More missing allocator-extended constructors for unordered > containers > + template<__detail::__container_compatible_range<value_type> _Rg> > + unordered_multimap(from_range_t, _Rg&& __rg, const allocator_type& > __a) > + : _M_h(0, hasher(), key_equal(), __a) > + { insert_range(std::forward<_Rg>(__rg)); } > + > template<__detail::__container_compatible_range<value_type> _Rg> > unordered_multimap(from_range_t, _Rg&& __rg, size_type __n, > const allocator_type& __a) > diff --git a/libstdc++-v3/include/bits/unordered_set.h > b/libstdc++-v3/include/bits/unordered_set.h > index 21ffdaf50a0..3b218f3394c 100644 > --- a/libstdc++-v3/include/bits/unordered_set.h > +++ b/libstdc++-v3/include/bits/unordered_set.h > @@ -294,6 +294,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER > : _M_h(__n, __hf, __eql, __a) > { insert_range(std::forward<_Rg>(__rg)); } > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 2713. More missing allocator-extended constructors for unordered > container > + template<__detail::__container_compatible_range<_Value> _Rg> > + unordered_set(from_range_t, _Rg&& __rg, const allocator_type& __a) > + : _M_h(0, hasher(), key_equal(), __a) > + { insert_range(std::forward<_Rg>(__rg)); } > + > template<__detail::__container_compatible_range<_Value> _Rg> > unordered_set(from_range_t, _Rg&& __rg, size_type __n, > const allocator_type& __a) > @@ -1265,6 +1272,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER > : _M_h(__n, __hf, __eql, __a) > { insert_range(std::forward<_Rg>(__rg)); } > > + > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 2713. More missing allocator-extended constructors for unordered > container > + template<__detail::__container_compatible_range<_Value> _Rg> > + unordered_multiset(from_range_t, _Rg&& __rg, const allocator_type& > __a) > + : _M_h(0, hasher(), key_equal(), __a) > + { insert_range(std::forward<_Rg>(__rg)); } > + > template<__detail::__container_compatible_range<_Value> _Rg> > unordered_multiset(from_range_t, _Rg&& __rg, size_type __n, > const allocator_type& __a) > diff --git > a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc > b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc > index b3cbb2e6062..51f8538669a 100644 > --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc > +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc > @@ -49,12 +49,11 @@ test_deduction_guide() > > using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>; > Alloc alloc; > - // LWG2713: there is no matching constructor > - // std::unordered_map m5(std::from_range, r, alloc); > - // static_assert(std::is_same_v< > - // decltype(m5), > - // std::unordered_map<long, float, > - // std::hash<long>, std::equal_to<long>, Alloc>>); > + std::unordered_map m5(std::from_range, r, alloc); > + static_assert(std::is_same_v< > + decltype(m5), > + std::unordered_map<long, float, > + std::hash<long>, std::equal_to<long>, Alloc>>); > > std::unordered_map m6(std::from_range, r, 0, alloc); > static_assert(std::is_same_v< > @@ -154,13 +153,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf) > VERIFY( is_equal(m9.hash_function(), hf) ); > VERIFY( is_equal(m9.key_eq(), eqf) ); > > - // LWG2713: there is no matching constructor > - // std::unordered_map<K, V, Hash, Equal, Alloc> > - // ma1(std::from_range, Range(a, a+14), alloc); > - // VERIFY( eq(ma1, {a, 9}) ); > - // VERIFY( is_equal(ma1.hash_function(), Hash()) ); > - // VERIFY( is_equal(ma1.key_eq(), Equal()) ); > - // VERIFY( ma1.get_allocator() == alloc ); > + std::unordered_map<K, V, Hash, Equal, Alloc> > + ma1(std::from_range, Range(a, a+14), alloc); > + VERIFY( eq(ma1, {a, 9}) ); > + VERIFY( is_equal(ma1.hash_function(), Hash()) ); > + VERIFY( is_equal(ma1.key_eq(), Equal()) ); > + VERIFY( ma1.get_allocator() == alloc ); > > std::unordered_map<K, V, Hash, Equal, Alloc> > ma2(std::from_range, Range(a, a+14), 2, alloc); > diff --git > a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc > b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc > index 9273ef0d57a..2e26cd2d201 100644 > --- > a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc > +++ > b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc > @@ -53,12 +53,11 @@ test_deduction_guide() > > using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>; > Alloc alloc; > - // LWG2713: there is no matching constructor > - // std::unordered_multimap m5(std::from_range, r, alloc); > - // static_assert(std::is_same_v< > - // decltype(m5), > - // std::unordered_multimap<long, float, > - // std::hash<long>, std::equal_to<long>, > Alloc>>); > + std::unordered_multimap m5(std::from_range, r, alloc); > + static_assert(std::is_same_v< > + decltype(m5), > + std::unordered_multimap<long, float, > + std::hash<long>, std::equal_to<long>, Alloc>>); > > std::unordered_multimap m6(std::from_range, r, 0, alloc); > static_assert(std::is_same_v< > @@ -159,13 +158,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf) > VERIFY( is_equal(m9.hash_function(), hf) ); > VERIFY( is_equal(m9.key_eq(), eqf) ); > > - // LWG2713: there is no matching constructor > - // std::unordered_multimap<K, V, Hash, Equal, Alloc> > - // ma1(std::from_range, Range(a, a+14), alloc); > - // VERIFY( eq(ma1, {a, 14}) ); > - // VERIFY( is_equal(ma1.hash_function(), Hash()) ); > - // VERIFY( is_equal(ma1.key_eq(), Equal()) ); > - // VERIFY( ma1.get_allocator() == alloc ); > + std::unordered_multimap<K, V, Hash, Equal, Alloc> > + ma1(std::from_range, Range(a, a+14), alloc); > + VERIFY( eq(ma1, {a, 14}) ); > + VERIFY( is_equal(ma1.hash_function(), Hash()) ); > + VERIFY( is_equal(ma1.key_eq(), Equal()) ); > + VERIFY( ma1.get_allocator() == alloc ); > > std::unordered_multimap<K, V, Hash, Equal, Alloc> > ma2(std::from_range, Range(a, a+14), 2, alloc); > diff --git > a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc > b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc > index fb388764423..ddbc7ff822f 100644 > --- > a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc > +++ > b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc > @@ -49,11 +49,10 @@ test_deduction_guide(long* p) > > using Alloc = __gnu_test::SimpleAllocator<long>; > Alloc alloc; > - // LWG2713: there is no matching constructor > - // std::unordered_multiset s5(std::from_range, r, alloc); > - // static_assert(std::is_same_v< > - // decltype(s5), > - // std::unordered_multiset<long, std::hash<long>, std::equal_to<long>, > Alloc>>); > + std::unordered_multiset s5(std::from_range, r, alloc); > + static_assert(std::is_same_v< > + decltype(s5), > + std::unordered_multiset<long, std::hash<long>, std::equal_to<long>, > Alloc>>); > > std::unordered_multiset s6(std::from_range, r, 0, alloc); > static_assert(std::is_same_v< > @@ -136,13 +135,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf) > VERIFY( is_equal(s9.hash_function(), hf) ); > VERIFY( is_equal(s9.key_eq(), eqf) ); > > - // LWG2713: there is no matching constructor > - // std::unordered_multiset<V, Hash, Equal, Alloc> > - // sa(std::from_range, Range(a, a+14), alloc); > - // VERIFY( eq(sa1, {a, 14}) ); > - // VERIFY( is_equal(sa1.hash_function(), Hash()) ); > - // VERIFY( is_equal(sa1.key_eq(), Equal()) ); > - // VERIFY( sa1.get_allocator() == alloc ); > + std::unordered_multiset<V, Hash, Equal, Alloc> > + sa1(std::from_range, Range(a, a+14), alloc); > + VERIFY( eq(sa1, {a, 14}) ); > + VERIFY( is_equal(sa1.hash_function(), Hash()) ); > + VERIFY( is_equal(sa1.key_eq(), Equal()) ); > + VERIFY( sa1.get_allocator() == alloc ); > > std::unordered_multiset<V, Hash, Equal, Alloc> > sa2(std::from_range, Range(a, a+14), 2, alloc); > diff --git > a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc > b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc > index c1acf143661..adc14a7b98a 100644 > --- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc > +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc > @@ -49,11 +49,10 @@ test_deduction_guide(long* p) > > using Alloc = __gnu_test::SimpleAllocator<long>; > Alloc alloc; > - // LWG2713: there is no matching constructor > - // std::unordered_set s5(std::from_range, r, alloc); > - // static_assert(std::is_same_v< > - // decltype(s5), > - // std::unordered_set<long, std::hash<long>, std::equal_to<long>, > Alloc>>); > + std::unordered_set s5(std::from_range, r, alloc); > + static_assert(std::is_same_v< > + decltype(s5), > + std::unordered_set<long, std::hash<long>, std::equal_to<long>, Alloc>>); > > std::unordered_set s6(std::from_range, r, 0, alloc); > static_assert(std::is_same_v< > diff --git a/libstdc++-v3/testsuite/std/ranges/conv/1.cc > b/libstdc++-v3/testsuite/std/ranges/conv/1.cc > index 231cb9d9934..2caa1b83f30 100644 > --- a/libstdc++-v3/testsuite/std/ranges/conv/1.cc > +++ b/libstdc++-v3/testsuite/std/ranges/conv/1.cc > @@ -12,6 +12,7 @@ > #include <testsuite_hooks.h> > #include <testsuite_allocator.h> > #include <testsuite_iterators.h> > +#include <unordered_map> > > void > test_p1206r7_examples() > @@ -478,6 +479,26 @@ test_pr119282() > return true; > } > > +void > +test_lwg2713() > +{ > + using Alloc = __gnu_test::uneq_allocator<std::pair<const int, const > char*>>; > + const Alloc alloc(303); > + const std::map<int, const char*> m{{1, "one"}, {2, "two"}, {3, "three"}}; > + namespace ranges = std::ranges; > + > + // Call constructors with bucket count > + auto m1 = m | ranges::to<std::unordered_map>(0, alloc); > + VERIFY( m1.get_allocator() == alloc ); > + auto m2 = m | ranges::to<std::unordered_multimap>(0, alloc); > + VERIFY( m2.get_allocator() == alloc ); > + // These call constructors added in lwg2713 > + auto m3 = m | ranges::to<std::unordered_map>(alloc); > + VERIFY( m3.get_allocator() == alloc ); > + auto m4 = m | ranges::to<std::unordered_multimap>(alloc); > + VERIFY( m4.get_allocator() == alloc ); > +} > + > int main() > { > test_p1206r7_examples(); > @@ -487,6 +508,7 @@ int main() > test_2_1_3(); > test_2_1_4(); > test_2_2(); > + test_lwg2713(); > test_lwg3984(); > test_nodiscard(); > test_constexpr(); > -- > 2.48.1 >