C++ Logo


Advanced search

Re: [std-proposals] In re: Issue2157

From: Ryan Nicholl <rnicholl_at_[hidden]>
Date: Thu, 7 Dec 2023 15:45:18 -0800
I would suggest allowing mutation of array<T const, 0>.

The reason why has really nothing to do with the interface, and more to do
with the fact that allowing this permits empty base class optimization of
array<T, 0>.

Implementing array<T, 0> as inheriting from _EmptyAggregate I think
provides the best opportunities for optimization.

My proposal for resolution is to remove the requirement that it consist of
a single member empty aggregate, and instead allow empty classes.

Under this proposal, implementation as an empty class is allowed, but not
required, and all major implementations would be permitted.

I would also remove the requirement that begin() and end() return "unique"
values, whatever that means. We should either explicitly allow nullptr as a
return value, or drop the requirement that std::array iterators are
contiguous iterators for std::array<T,0>.

On Thu, Dec 7, 2023 at 3:27 PM Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>

> On Thu, Dec 7, 2023 at 2:00 AM Jens Maurer <jens.maurer_at_[hidden]> wrote:
>> On 05/12/2023 22.36, Arthur O'Dwyer via Std-Proposals wrote:
>> > On Tue, Dec 5, 2023 at 4:03 PM Ryan Nicholl via Std-Proposals <
>> std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>>
>> wrote:
>> >
>> > I want to raise my personal concern around the proposed solution
>> to Issue2157.
>> >
>> > I do not believe that std::array<T, 0> {{}}; should be required to
>> be valid syntax. This prevents std::array<T, 0> from being implemented as
>> an empty struct. It is also just logically inconsistent with an array that
>> contains no elements. I believe this eliminates empty base class
>> optimization and presents several other issues that I believe diverge from
>> the 0 overhead principle. For this reason I think the solution ought to be
>> reconsidered.
>> >
>> >
>> > (You're talking about LWG 2157 <
>> https://cplusplus.github.io/LWG/issue2157>, "How does std::array<T,0>
>> initialization work when T is not default-constructible?".)
>> >
>> > There are two caveats you don't seem to be taking into account:
>> > (1) No user-programmer ever should write `array<T,0> t = {{}};` —
>> `array`, like every other STL container and algebraic type, is intended to
>> be used with a single pair of braces `array<T,0> t = {};`. Yes, in
>> all present-day library implementations this relies on brace elision <
>> https://eel.is/c++draft/dcl.init.aggr#16.sentence-1>; that's okay.
>> > (2) No library vendor implements `array<T,0>` as an empty type.
>> >
>> > Asking for `array<T,0>` to be "maybe empty, maybe not" would cause
>> (minor) pain for user-programmers. Asking for it to be "always empty" would
>> cause (major ABI-breaking) pain for vendors. The proposed resolution of LWG
>> 2157 seems to fix some infelicities in the current wording, without causing
>> pain for (1) any user-programmer or (2) any existing vendor. So it seems
>> like an improvement to me.
> I take this back: LWG2157's P/R is a breaking change for (at least)
> libc++, because it proposes [emphasis added; this whole sentence is
> inserted in the P/R]:
> > A zero-sized array type is an aggregate [...]. There is a single element
> of the aggregate, of an unspecified *empty* aggregate type.
> libc++'s single member is an aggregate (a char array), but it's not an
> empty aggregate.
> So LWG 2157 is already proposing to break vendors — so I withdraw my
> "seems like an improvement." As long as we're paying for the ABI break
> anyway, it might be worth looking for an even more aggressively better P/R.
> A consistency point of view:
>> T * p = new T[n];
>> (where n might be a constant or not)
>> is now required to have T default constructible even if n = 0. CWG 2102
>> <https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2102>.
> That's a different (and perhaps even deeper) can of worms, right?
> We currently lack specification for whether any of these expressions are
> supposed to work:
> std::array<const int, 0> ca = {}; // OK
> std::array<const int, 0> cb; // unclear; libc++ and *Microsoft* reject;
> *libstdc++* accepts
> ca = ca; // unclear; libc++ and Microsoft reject; libstdc++ accepts
> ca.fill(42); // unclear; libc++ and *libstdc++* reject; *Microsoft*
> accepts
> ca.swap(ca); // unclear; libc++ and libstdc++ reject; Microsoft accepts
> Is there yet an LWG issue to clarify the well-formedness of the "mutating"
> member functions of array<const T, N>?
> Thanks,
> Arthur

Received on 2023-12-07 23:45:32