https://gcc.gnu.org/g:997d2f4877b0ccf337dd8c340a2ca161d5c65728
commit r17-4991-g997d2f4877b0ccf337dd8c340a2ca161d5c65728 Author: Tomasz KamiĆski <[email protected]> Date: Thu Oct 8 12:00:48 2026 +0200 libsdc++: Use emplace_hint instead of emplace in ranges::to. Implements LWG4121, "ranges::to constructs associative containers via c.emplace(c.end(), *it)". Using emplace_hint(it, arg) provides support for associative container without from_range constructor, from which emplace(it, arg) constructrs elements from it, arg. All statndard sequence containers that provides emplace(it, arg) overload, provides push_back/emplace_back and are handled by eariel branches. libstdc++-v3/ChangeLog: * include/std/ranges (ranges::to): Replace emplace(__c.end(), *__it) with emplace_hint(__c.end(), *__it) * testsuite/std/ranges/conv/1.cc: Update tests accordingly. Reviewed-by: Jonathan Wakely <[email protected]> Diff: --- libstdc++-v3/include/std/ranges | 8 ++-- libstdc++-v3/testsuite/std/ranges/conv/1.cc | 60 +++++++++++++++-------------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 37f048e3d0d3..5963647c3787 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -9563,7 +9563,9 @@ namespace __detail __c.reserve(static_cast<range_size_t<_Cont>>(ranges::size(__r))); // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4016. container-insertable checks do not match what - // container-inserter does + // container-inserter does + // 4121. ranges::to constructs associative containers + // via c.emplace(c.end(), *it) auto __it = ranges::begin(__r); const auto __sent = ranges::end(__r); while (__it != __sent) @@ -9572,8 +9574,8 @@ namespace __detail __c.emplace_back(*__it); else if constexpr (requires { __c.push_back(*__it); }) __c.push_back(*__it); - else if constexpr (requires { __c.emplace(__c.end(), *__it); }) - __c.emplace(__c.end(), *__it); + else if constexpr (requires { __c.emplace_hint(__c.end(), *__it); }) + __c.emplace_hint(__c.end(), *__it); else __c.insert(__c.end(), *__it); ++__it; diff --git a/libstdc++-v3/testsuite/std/ranges/conv/1.cc b/libstdc++-v3/testsuite/std/ranges/conv/1.cc index 2caa1b83f30f..14b52f6dd3ca 100644 --- a/libstdc++-v3/testsuite/std/ranges/conv/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/conv/1.cc @@ -9,6 +9,7 @@ #include <list> #include <forward_list> #include <map> +#include <set> #include <testsuite_hooks.h> #include <testsuite_allocator.h> #include <testsuite_iterators.h> @@ -204,13 +205,13 @@ test_2_1_3() VERIFY( c2.c.get_allocator() == Alloc(78) ); } -enum AppendKind { None, EmplaceBack, PushBack, Emplace, Insert }; +enum AppendKind { None, EmplaceBack, PushBack, EmplaceHint, Insert }; template<typename C, AppendKind Kind> struct Cont4 { // Only support construction with no args or an allocator. - // This forces the use of either emplace_back, push_back, emplace or insert. + // This forces the use of either emplace_back, push_back, emplace_hint or insert. Cont4() { } Cont4(typename C::allocator_type a) : c(a) { } @@ -235,13 +236,13 @@ struct Cont4 } template<typename T> - requires (Kind <= Emplace) - && requires(C& c, T&& t) { c.emplace(c.end(), std::forward<T>(t)); } + requires (Kind <= EmplaceHint) + && requires(C& c, T&& t) { c.emplace_hint(c.end(), std::forward<T>(t)); } void - emplace(typename C::iterator pos, T&& t) + emplace_hint(typename C::iterator pos, T&& t) { - kind = Emplace; - c.emplace(pos, std::forward<T>(t)); + kind = EmplaceHint; + c.emplace_hint(pos, std::forward<T>(t)); } template<typename T> @@ -287,6 +288,7 @@ test_2_1_4() using Alloc2 = __gnu_test::uneq_allocator<short>; using V = std::vector<int, Alloc>; using List = std::list<short, Alloc2>; + using Set = std::set<int>; std::list<unsigned> l{1u, 2u, 3u}; std::list<long> l2{4l, 5l, 6l}; @@ -337,30 +339,30 @@ test_2_1_4() VERIFY( c6.kind == PushBack ); VERIFY( ! c6.used_reserve ); - // use vector::emplace and vector::reserve - auto c7 = std::ranges::to<Cont4<V, Emplace>>(l); - static_assert(std::is_same_v<decltype(c7), Cont4<V, Emplace>>); - VERIFY( c7.c == V(l.begin(), l.end()) ); - VERIFY( c7.kind == Emplace ); - VERIFY( c7.used_reserve ); - - // use vector::emplace and vector::reserve - auto c8 = std::ranges::to<Cont4<V, Emplace>>(l2, Alloc(78)); - static_assert(std::is_same_v<decltype(c8), Cont4<V, Emplace>>); - VERIFY( c8.c == V(l2.begin(), l2.end()) ); - VERIFY( c8.c.get_allocator() == Alloc(78) ); - VERIFY( c8.kind == Emplace ); - VERIFY( c8.used_reserve ); - - // use list::emplace - auto c9 = std::ranges::to<Cont4<List, Emplace>>(c.c, Alloc2(99)); - static_assert(std::is_same_v<decltype(c9), Cont4<List, Emplace>>); - VERIFY( c9.c == List(l.begin(), l.end()) ); - VERIFY( c9.c.get_allocator() == Alloc(99) ); - VERIFY( c9.kind == Emplace ); + // use list::emplace_back + auto c7 = std::ranges::to<Cont4<List, EmplaceBack>>(c.c, Alloc2(99)); + static_assert(std::is_same_v<decltype(c7), Cont4<List, EmplaceBack>>); + VERIFY( c7.c == List(l.begin(), l.end()) ); + VERIFY( c7.c.get_allocator() == Alloc(99) ); + VERIFY( c7.kind == EmplaceBack ); + VERIFY( ! c7.used_reserve ); + + // use set::emplace_hint + auto c8 = std::ranges::to<Cont4<Set, EmplaceHint>>(l); + static_assert(std::is_same_v<decltype(c8), Cont4<Set, EmplaceHint>>); + VERIFY( c8.c == Set(l.begin(), l.end()) ); + VERIFY( c8.kind == EmplaceHint ); + VERIFY( ! c8.used_reserve ); + + // use set::emplace_hint + auto c9 = std::ranges::to<Cont4<Set, EmplaceHint>>(l2, Alloc(78)); + static_assert(std::is_same_v<decltype(c9), Cont4<Set, EmplaceHint>>); + VERIFY( c9.c == Set(l2.begin(), l2.end()) ); + VERIFY( c9.c.get_allocator() == Alloc(78) ); + VERIFY( c9.kind == EmplaceHint ); VERIFY( ! c9.used_reserve ); - // use vector::insert and vector::reserve + // use vector::insert and vector::reserve auto c10 = std::ranges::to<Cont4<V, Insert>>(l); static_assert(std::is_same_v<decltype(c10), Cont4<V, Insert>>); VERIFY( c10.c == V(l.begin(), l.end()) );
