C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::initializer_list constructor for stack and queue

From: Matthew Satti <matthewsatti_at_[hidden]>
Date: Fri, 21 Feb 2025 07:28:33 +0800
Interesting, given
  std::stack<int> s = {1, 2, 3};
I would've naturally assumed the opposite, the first element in the
initializer_list is the first to push.
To me that makes it more consistent with LIFO behaviour where the last
element in the list is the first to pop.

Thanks for the background context, I'll think about it a bit more.

On Fri, 21 Feb 2025 at 06:01, Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
wrote:

> On Thu, Feb 20, 2025 at 7:16 AM Jonathan Wakely via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> On Thu, 20 Feb 2025 at 11:46, Matthew Satti via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> Hi there,
>>>
>>> I was wondering about adding std::initializer_list constructor overloads
>>> for std::queue, std::stack, and std::priority_queue. Has there been any
>>> proposals regarding this?
>>>
>>
>> It already works with an extra pair of parens:
>> std::stack<int> s({1,2,3,4});
>> This matches the stack(Container&&) constructor.
>>
>
> But if it works with an extra pair of parens, then it should probably also
> work without. This seems similar to the situation we were in with
> `std::span<const int>` prior to P2447
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2447r6.html>:
> that `{{1,2,3}}` worked but `{1,2,3}` didn't.
>
> Now, *originally*, in the C++11 cycle, I believe there was a strong
> rationale why
> std::stack<int> s = {1,2,3};
> was not made to Just Work. The reason is that it's not obvious whether
> this should put 1 on the top of the stack and 3 on the bottom, or vice
> versa. As a programmer, I would naturally assume that the "first" element
> of the stack's initializer list would be the "first" to pop; but it turns
> out that in fact we push and pop from the *back* of a stack, not the
> front, so this initialization would actually put 3 on the top of the stack
> and 1 on the bottom. This is confusing for at least 50% of the population.
> So we wisely designed std::stack *not* to be initializable from an
> initializer list. For the same reason, we didn't allow this to work:
> int a[] = {1,2,3};
> std::stack<int> s(a, a+3);
> because again it was unclear what order this would actually leave the
> elements in. (Although admittedly here it's a little more obvious,
> because of how C++ iterators work, that the only sane/implementable
> behavior is "push 1, then push 2, then push 3," leaving 3 at the top of the
> stack.)
>
> *C++23 added* range constructors and iterator-pair constructors:
> - https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1425r4.pdf
> - https://en.cppreference.com/w/cpp/container/stack/stack
> This blew the old rationale out of the water. (Wrongly, IMHO, as the old
> rationale still applied; but it's too late to debate now.)
>
> So at this point I agree with Matthew: there's no good reason for C++ to
> permit
> int a[] = {1,2,3};
> std::stack<int> s(a, a+3);
> but to forbid the direct initialization
> std::stack<int> s = {1,2,3};
>
> It would be reasonable to bring a proposal for that. However, I could see
> a counterargument that we should "salvage what we can" — we should never
> have added the iterator-pair constructor, but at least we can avoid
> *compounding* that error at this point. Anyone bringing a proposal for
> `stack(initializer_list)` should make sure to robustly discuss that
> objection in their paper.
>
> my $.02,
> –Arthur
>

Received on 2025-02-20 23:28:37