Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Order of designated initializers in C++20

47 views
Skip to first unread message

Juha Nieminen

unread,
Sep 2, 2019, 5:44:33 AM9/2/19
to
In C you can use designated initializers to initialize a struct
(or an array). There is no requirement for the order in which
the initializers are listed, so it's completely ok to list them
in a different order than they are declared in the struct.
So you can have:

struct S { int a, b; };
struct S s = { .b = 1, .a = 2 };

In C++20, however, you cannot list the initializers in the "wrong"
order.

Why?

It would be highly convenient that designated initializers wouldn't
need to be in the same order as the variables declared in the struct.
For example, the variables may be declared in one order in the struct
based on efficiency (the order of member variables may affect the
size of the struct), but listed in an initialization in another, eg.
grouped logically based on role.

Moreover, and more importantly, later changing the order of the
variables in the struct will not break the initialization (which I think
is one of the main motivations for it having been introduced in the
first place).

Why does C++20 impose this restriction?

I understand that C++ wants to initialize member variables in the order
they are declared inside the struct/class. However, I don't see why this
should affect designated initializers.

If listing the designated initializers in the "wrong" order is some kind
of problem when it comes to initialization values with side-effects, the
standard could simply state that if the designated initializers are not
listed in the same order as declared in the struct, the order of evaluation
of the values is not guaranteed and implementation-defined. However, it
doesn't need to outright forbid it. (After all, there are other situations
as well, where order of evaluation is not guaranteed, such as when giving
parameters to a function.)

I don't know what the C standard says about what happens when designated
initializers are not in the same order as in the declaration of the struct,
but at least clang seems to simply evaluate the values in the same order
as the latter, so it doesn't seem to be a problem.

James Kuyper

unread,
Sep 2, 2019, 10:20:53 AM9/2/19
to
On 9/2/19 5:44 AM, Juha Nieminen wrote:
> In C you can use designated initializers to initialize a struct
> (or an array). There is no requirement for the order in which
> the initializers are listed, so it's completely ok to list them
> in a different order than they are declared in the struct.
> So you can have:
>
> struct S { int a, b; };
> struct S s = { .b = 1, .a = 2 };
>
> In C++20, however, you cannot list the initializers in the "wrong"
> order.
...
> I don't know what the C standard says about what happens when designated
> initializers are not in the same order as in the declaration of the struct,

I can't answer your other questions, but I can answer that one. This is
no such restriction in C on the order in which designators are written,
and here's what C2011 says about the order in which the resulting
initializations occur:

"... When no designations are present, subobjects of the current object
are initialized in order according to the type of the current object:
array elements in increasing subscript order, structure members in
declaration order, and the first named member of a union. In contrast, a
designation causes the following initializer to begin initialization of
the subobject described by the designator. Initialization then continues
forward in order, beginning with the next subobject after that described
by the designator." (6.7.8p17).

Thus, a designation causes a jump in the initialization order, after
which initialization moves forward as normal from the new position. You
could, as a result, end up initializing the same element or an array, or
the same member of a struct, multiple times. I would expect to see such
code only in the obfuscated C contest or in machine generated code, but
it is permitted.

Paavo Helde

unread,
Sep 2, 2019, 10:25:22 AM9/2/19
to
So you propose that code pieces should be evaluated at a different order
than written. We already have a bad case of such silent code reordering
with the initialization lists, the committee probably did not want to
repeat that mishap.


Bonita Montero

unread,
Sep 2, 2019, 11:13:43 AM9/2/19
to
> In C you can use designated initializers to initialize a struct
> (or an array). There is no requirement for the order in which
> the initializers are listed, so it's completely ok to list them
> in a different order than they are declared in the struct.
> So you can have:
> struct S { int a, b; };
> struct S s = { .b = 1, .a = 2 };
> In C++20, however, you cannot list the initializers in the "wrong"
> order.

I think this does help to read the initialization of a structure
because you can read it in the order as it is defined in the
structure. So if you read the initialization and have the defi-
nition open in another window, that's a more convenient read-
ability.

> It would be highly convenient that designated initializers wouldn't
> need to be in the same order as the variables declared in the struct.
> For example, the variables may be declared in one order in the struct
> based on efficiency (the order of member variables may affect the
> size of the struct), but listed in an initialization in another, eg.
> grouped logically based on role.

Convenience isn't determined in efficiency.
And if you won't have a POD you can't rely on a certain layout anyway.

> Moreover, and more importantly, later changing the order of the
> variables in the struct will not break the initialization (which
> I think is one of the main motivations for it having been introduced
> in the first place).

Ok, that's a proper reason; but as I said above, this would lead to
less readable code because the inizialization isn't synchronous with
the definition.

Richard Damon

unread,
Sep 2, 2019, 5:48:34 PM9/2/19
to
On 9/2/19 5:44 AM, Juha Nieminen wrote:
My first guess is that they found that the fact that initializer lists
in constructors allowed things to be specified out of order caused
enough problems (but was allowed from the beginning so too much code did
it) that they didn't want to repeat the mistake.

I am not familiar with how C++ will implement this, but if the
initializers are going to be run time expressions, and thus able to
reference other members of the struct (like initializer lists can) then
the problem is real.

Juha Nieminen

unread,
Sep 3, 2019, 10:08:02 AM9/3/19
to
Paavo Helde <myfir...@osa.pri.ee> wrote:
> So you propose that code pieces should be evaluated at a different order
> than written. We already have a bad case of such silent code reordering
> with the initialization lists, the committee probably did not want to
> repeat that mishap.

I don't really care in which order the parameters are evaluated and the
elements initialized. The standard could just as well say that if the
designated initializers are not listed in the same order as they are
declared in the struct, then the order of evaluation and initialization
is implementation-defined, and allow the compiler do whatever it wants
with respect to that order.

Juha Nieminen

unread,
Sep 3, 2019, 10:14:09 AM9/3/19
to
Bonita Montero <Bonita....@gmail.com> wrote:
> Ok, that's a proper reason; but as I said above, this would lead to
> less readable code because the inizialization isn't synchronous with
> the definition.

I don't think it would lead to less readable code.

The members of a struct may be declared in an "illogical" order because
of efficiency reasons. The order of these elements may affect the size
of the struct (grouping small elements may make the struct smaller,
compared to the situation where large and small elements are declared
in alternation).

However, in an initialization you may want to list the elements in a
more logical order, eg. based on role or meaning. For example if two
members are closely related, you may want to list them consecutively
in the initialization (even if they aren't consecutive inside the
struct, for space efficiency reasons).

And, of course, as said, if you ever change the order of the member
variables (eg. to optimize the size of the struct), it wouldn't break
designated initializers.

Öö Tiib

unread,
Sep 3, 2019, 10:17:57 AM9/3/19
to
I would like diagnostic (like lot of compilers give on case of
misordered initializer lists) and sure, if wrong order is ill-formed
then compiling it is implementation-defined extension.

Bonita Montero

unread,
Sep 3, 2019, 1:48:46 PM9/3/19
to
> The members of a struct may be declared in an "illogical"
> order because of efficiency reasons.

That might be sometimes so, f.e. when declaring serialized
data-structures, but that's not typical.

Scott Lurndal

unread,
Sep 3, 2019, 4:33:22 PM9/3/19
to
In your, what appears to be, extremely limited experience.

The standards bodies; POSIX, for example, don't even define
the order of structure members in structures that are part of
the C bindings; it's left to the implementation (or the associated
application binary interface (ABI)) to define the order and any
padding.

Part of the reason that C/C++ don't impose an ordering on
designated structure initializers is because the order may differ between
implementations, thus any source code that assumed a particular order
in an initializer wouldn't be portable.

Bonita Montero

unread,
Sep 4, 2019, 12:56:05 AM9/4/19
to
>> That might be sometimes so, f.e. when declaring serialized
>> data-structures, but that's not typical.

> In your, what appears to be, extremely limited experience.

My experience is not limited on that.

> The standards bodies; POSIX, for example, don't even define
> the order of structure members in structures that are part of
> the C bindings; it's left to the implementation (or the associated
> application binary interface (ABI)) to define the order and any
> padding.

That' proves that this is typical?
In C++ you usually don't even insitialize members of structures
or classes like this by hand but indirectly through a constructor.

Juha Nieminen

unread,
Sep 4, 2019, 9:49:13 AM9/4/19
to
Bonita Montero <Bonita....@gmail.com> wrote:
> In C++ you usually don't even insitialize members of structures
> or classes like this by hand but indirectly through a constructor.

The problem is that the declaration/implementation of the struct might
not be modifiable (eg. because it's in a third-party library), and in
some situations the members might not be assignable, most typically
because you want/need the instantiation to be const (or even constexpr):

const Data kData = { .value = 5, .name = "hello" };

Of course you could go the long route of creating a "constructor" function
for it and use it to initialize the const object:

Data createData(int value, const char* name)
{
Data data;
data.value = value;
data.name = name;
return data;
}

...

const Data kData = createData(5, "hello");

but that's a long-winded way of doing it.

Bonita Montero

unread,
Sep 4, 2019, 10:03:04 AM9/4/19
to
>> In C++ you usually don't even insitialize members of structures
>> or classes like this by hand but indirectly through a constructor.

> The problem is that the declaration/implementation of the struct might
> not be modifiable (eg. because it's in a third-party library), and in
> some situations the members might not be assignable, most typically
> because you want/need the instantiation to be const (or even constexpr):

One solution would be to derive a class from the structure and have
a constructor on it. The APIs evaluating the structure will get the
upcasted structure.

> const Data kData = { .value = 5, .name = "hello" };
> Of course you could go the long route of creating a "constructor" function
> for it and use it to initialize the const object:
> Data createData(int value, const char* name)
> {
> Data data;
> data.value = value;
> data.name = name;
> return data;
> }
> ...
> const Data kData = createData(5, "hello");
> but that's a long-winded way of doing it.

Ok, you're right. That's days of work!

Bonita Montero

unread,
Sep 4, 2019, 11:23:04 AM9/4/19
to
>>> In C++ you usually don't even insitialize members of structures
>>> or classes like this by hand but indirectly through a constructor.

>> The problem is that the declaration/implementation of the struct might
>> not be modifiable (eg. because it's in a third-party library), and in
>> some situations the members might not be assignable, most typically
>> because you want/need the instantiation to be const (or even constexpr):

> One solution would be to derive a class from the structure and have
> a constructor on it. The APIs evaluating the structure will get the
> upcasted structure.

BTW: Maybe this could fail if the API requires an array of structures.
Or is it guaranteed that a derived class without any data-members always
has the same size as the base-class? Practically this will apply to all
compilers, but theoretically that might not be correct.

0 new messages