C++ Logo

std-proposals

Advanced search

Re: [std-proposals] better container::append_range?

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sat, 15 Nov 2025 13:19:15 -0500
On Sat, Nov 15, 2025 at 12:44 PM Jonathan Wakely via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On Sat, 15 Nov 2025 at 06:33, Hewill Kang via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>>
>> In C++23, we can use `append_range` to append ranges to a container more
>> intuitively and simply. Its function signature is as follows (from
>> https://eel.is/c++draft/containers)
>> ```
>> template<container-compatible-range<T> R>
>> constexpr void append_range(R&& rg);
>> ```
>> So we can:
>> ```
>> std::vector<int> v;
>> v.append_range(std::views::iota(0, 5));
>> ```
>>
>> I think there are two areas for improvement.
>> First, it would be great to provide a default template to support
>> `initializer_list`:
>>
>> ```
>> template<container-compatible-range<T> R = initializer_list<T>>
>> constexpr void append_range(R&& rg);
>> ```
>>
>> which would make it more convenient for users:
>>
>> ```
>> std::vector<int> v;
>> v.append_range({1, 2, 3, 4});
>> ```
>>
>
> How often do you want to append a hardcoded list of values though?
> Initializer lists are useful for construction, when you often want to
> populate a container to a known set of values. I can't think of many times
> when I've wanted to append a known set of values to an existing container.
> Maybe you would want to use it in a variadic function template to append a
> pack:
> v.append_range({vals...});
> But even that seems quite niche, and you can do:
> v.append_range(std::initializer_list{vals...});
>

(`std::initializer_list<T>{vals...}`, that is, to avoid the pitfall of CTAD
deducing the wrong type when T is a specialization of `initializer_list`
and there's only one element in `vals`.)

This does seem somewhat in keeping with the direction of P2248 "Enabling
list-initialization for algorithms,"
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2248r8.html> except
that P2248 was only about permitting things like
    std::ranges::find(vector_of_pairs, {1,2})
and not things like
    std::ranges::set_intersection(vector_of_ints, {1,2,3})
. I thought there'd been a little discussion of the latter, but I don't see
such discussion in P2248R8, anyway.


Additionally, it might be more valuable if it could return `*this` instead
>> of `void` [...]
>> which can provide a chain operation for users
>>
>
Definitely not. That kind of "chaining" is essentially never useful in
practice, and merely serves to (1) make the function's implementation one
line longer and (2) make the codegen/register-pressure inside the function
very marginally worse. It also leads to antipatterns on the caller side: it
tempts users to write
    Object f(Object o) { return o.chained(); } // makes a copy of `o`
as opposed to forcing the more efficient
    Object f(Object o) { o.chained(); return o; } // moves from `o`
And, unless I'm mistaken, `.append_range` is part of the container
requirements now, which means users will sometimes have to implement it
themselves for their own containers. We *must not* force these infelicities
and inefficiencies on them; we must at least *allow* them to write optimal
code.

–Arthur

Received on 2025-11-15 18:19:30