C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Mandate layout of std::array

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Fri, 30 Jun 2023 22:35:35 -0400
On Fri, Jun 30, 2023 at 9:34 PM Julien Villemure-Fréchette via
Std-Proposals <std-proposals_at_[hidden]> wrote:

> If I remember correctly , std::array is an aggregate type that directly
> wraps a single data member of a built-in array type. Although it may not
> explicitly stated that it has the same layout as a C style array, this
> property should be deductible from other explicitly state clauses. For
> instance, since initialization of std::array is aggregate initializing the
> elements, then there is no vptr or vbaseptr (because this would disqualify
> the type as an aggregate).
>

std::array is an aggregate type, but its fields are not necessarily "a
single field which is an array." There's no actual wording that stops a
hostile implementation from implementing e.g.
    template<class T> struct array<T, 1> { T first; };
    template<class T> struct array<T, 2> { T first; T second; };
    template<class T> struct array<T, 3> { T first; T second; T third; };
on a target where the implementation permits aliasing between those and an
array of T (so that `data()[1]` still works). (I.e. all targets in
practice, but not the abstract machine in theory.)
What wording there is, is in https://eel.is/c++draft/array#overview-2 .
Vendors are required to make list-initialization like
    std::array<int, 3> a = {1,2,3};
work according to the aggregate initialization rules, but that's
pretty much all she wrote.

Now, the wording is probably as vague as it is simply because otherwise
[array.zero] <https://eel.is/c++draft/array#zero> would have to be *more*
complicated. You can't say "an object of type std::array<T, 0> is an
aggregate with a single member of type T[0]", because T[0] is not a type.
So you'd have to say "array<T,0> is an empty type"... except you can't say
that, because empirically vendors haven't done that. libc++ just had this
conversation
<https://cpplang.slack.com/archives/CM2HTSZ6G/p1684068423598729> in May.[*]
The idea seems to have been that we wanted a double-braced `{{ts...}}` to
be a valid initializer for `std::array` for all `ts...`, and that's
possible only if `std::array<T,0>` is not an empty type. *Should* we have
done that? *Would* we do that today? No, of course not. But back then I
guess it seemed like a good idea.

So for Brian's proposal, `array<T,0>` will still have to be a special case;
unless you can sell vendors on breaking API compatibility for `array<T,0>`.
I don't know how easy or difficult that might be.

Personally I don't know of any practical use-cases for aliasing between
`array` and a C-style array. I agree it seems like it *should* work,
anyway. But the only precedent we have for that IIUC is
[complex.numbers.general]
<https://eel.is/c++draft/complex.numbers#general-4>, and I've always had
the (unsubstantiated) impression that [complex.numbers.general] was Widely
Regarded as a Bad Move. I don't think we should clone it without a *good*
reason.

my $.02,
Arthur
[* — anyone who needs a Slack invite, just ping me]

Received on 2023-07-01 02:35:49