On Thu, 8 Oct 2026 at 11:19, Tomasz Kamiński <[email protected]> wrote:
>
> 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.
> ---
> Testing on x86_64-linux. *ranges* test already passed in all
> standard modes. OK for trunk when all test passes?

OK


>
>  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 37f048e3d0d..5963647c378 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 2caa1b83f30..14b52f6dd3c 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()) );
> --
> 2.55.0
>

Reply via email to