Date: Sun, 16 Nov 2025 23:47:18 +0800
My habitual mental model is that functions returning a certain value are
always better than returning void because they carry more information.
But after your explanation, I learned that sometimes returning void might
be more meaningful.
Thanks for the feedback.
Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> 於
2025年11月16日 週日 上午2:19寫道:
> 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
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
always better than returning void because they carry more information.
But after your explanation, I learned that sometimes returning void might
be more meaningful.
Thanks for the feedback.
Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> 於
2025年11月16日 週日 上午2:19寫道:
> 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
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2025-11-16 15:47:33
