Why Does C++11 Not Support Designated Initializer Lists as C99

Why does C++11 not support designated initializer lists as C99?

C++ has constructors. If it makes sense to initialize just one member then that can be expressed in the program by implementing an appropriate constructor. This is the sort of abstraction C++ promotes.

On the other hand the designated initializers feature is more about exposing and making members easy to access directly in client code. This leads to things like having a person of age 18 (years?) but with height and weight of zero.


In other words, designated initializers support a programming style where internals are exposed, and the client is given flexibility to decide how they want to use the type.

C++ is more interested in putting the flexibility on the side of the designer of a type instead, so designers can make it easy to use a type correctly and difficult to use incorrectly. Putting the designer in control of how a type can be initialized is part of this: the designer determines constructors, in-class initializers, etc.

Can a designated initializer legally refer to the variable it's initializing in C99?

This foot-note


  1. In particular, the evaluation order need not be the same as the
    order of subobject initialization

for this quote

23 The evaluations of the initialization list expressions are
indeterminately sequenced with respect to one another and thus the
order in which any side effects occur is unspecified.152)

means that such an initialization like this

foo bar = {
.a = 3,
.b = bar.a + 3,
};

invokes undefined behavior because the expression bar.a + 3 can be evaluated before the initialization of the data member a.

The undefined behavior in particularly is defined like

Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results

Designated initializers in C++20

According to the C++ 20 Standard (9.3.1 Aggregates. p. #3)

(3.1) — If the initializer list is a designated-initializer-list, the
aggregate shall be of class type, the identifier in each designator
shall name a direct non-static data member of the class
, and the
explicitly initialized elements of the aggregate are the elements that
are, or contain, those members.

So you may not use the designated initializer list to initialize data members of base classes.

Use instead the usual list initialization like

Employee e1{ "John", "Wick", 40, 50000 };

or

Employee e1{ { "John", "Wick", 40 }, 50000 };

or as @Jarod42 pointed in a comment you can write

Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };

In this case the direct base class is initialized by a designated initializer list while the class Employe in whole is initialised by a non-designated initializer list.

Designated Initializers in C99: How to handle empty uninitialized struct members in C11?

how do I handle members that are not initialized?

The feature you describe is called designated initializers and was introduced in C99. It is not supported by C++. All members that are not initialized explicitly are guaranteed to be set to zero (*).

Maybe you didn't consider it, but the same applies to regular struct initialization as well. Example:

typedef struct
{
int a;
int b;
} ab;

ab mystruct = { .a = 1 }; // a is 1, b is guaranteed to be 0
ab mystruct = { 1 }; // a is 1, b is guaranteed to be 0

(The last example is also true for C++.)

This language rule is the reason why we can initialize all elements in a struct/array to zero by typing:

ab mystruct = { 0 };

because it actually means "set a to zero, and let then all other elements be implicitly initialized to zero".


(*) Formally, they are initialized as if they had static storage duration, i.e. data gets set to zero, pointers get set to NULL etc. C11 6.7.9/10.

What is the C++ equivalent to C's designated initializers?

No, C++ does not support C99's designated initializers. If you want to set individual members by name, you'll need to do it via assignment, e.g.

MyStruct test_struct = MyStruct();
test_struct.name = "buffer";
test_struct.func1 = test_func1;

C++ Equivalent to Designated Initializers?

I'm not sure you can do it in C++. For the stuff that you need to initialize using designated initializers, you can put those separately in a .c file compiled as C99, e.g.:

// In common header file
typedef union my_union
{
int i;
float f;
} my_union;

extern const my_union g_var;

// In file compiled as C99
const my_union g_var = { .f = 3.14159f };

// Now any file that #include's the header can access g_var, and it will be
// properly initialized at load time

Why C++20 doesn't support out-of-order designated initializer?

Yes, the rationale is covered in Annex C (informative)
Compatibility
specifically [diff.dcl]p10 (emphasis mine):

Affected subclause: [dcl.init.aggr] Change: In C++, designated
initialization support is restricted compared to the corresponding
functionality in C. In C++, designators for non-static data members
must be specified in declaration order, designators for array elements
and nested designators are not supported, and designated and
non-designated initializers cannot be mixed in the same initializer
list. Example:

struct A { int x, y; };
struct B { struct A a; };
struct A a = {.y = 1, .x = 2}; // valid C, invalid C++
int arr[3] = {[1] = 5}; // valid C, invalid C++
struct B b = {.a.x = 0}; // valid C, invalid C++
struct A c = {.x = 1, 2}; // valid C, invalid C++

Rationale: In C++, members are destroyed in reverse construction order and the elements of an initializer list are evaluated in lexical order, so field initializers must be specified in order.
Array designators conflict with lambda-expression syntax.
Nested designators are seldom used.

The first revision of the proposal also discusses this topic:

To meet these expectations for guaranteed copy elision, we require the designators to appear
as a subsequence of the data member declaration sequence, so that the evaluation order
matches the declaration order, and it is also textually left­to­right in designated initialization

You can obtain the last revision here.

Why are designated initializers not implemented in g++

As I noted in a comment, G++ doesn't support C99 standard designated initialisers, but it does support the GNU extension to C90 which allows designated initialisers. So this doesn't work:

union value_t {
char * v_cp;
float v_f;
};
union value_t my_val = { .v_f = 3.5f };

But this does:

union value_t my_val = { v_f: 3.5f };

This seems to be a bad interaction of co-ordination between the C and C++ standards committees (there is no particularly good reason why C++ doesn't support the C99 syntax, they just haven't considered it) and GCC politics (C++ shouldn't support C99 syntax just because it's in C99, but it should support GNU extension syntax that achieves exactly the same thing because that's a GNU extension that can be applied to either language).

Why has Clang decided to allow designated initializers in C++?

When compiled with -pedantic these warnings are generated:

source_file.cpp:3:18: warning: designated initializers are a C99 feature [-Wc99-extensions]
int a[6] = { [4] = 29, [2] = 15 };
^~~~~~~~
source_file.cpp:3:28: warning: designated initializers are a C99 feature [-Wc99-extensions]
int a[6] = { [4] = 29, [2] = 15 };

It is clear that clang++ by default enables c99-extensions.

This is not a bug as compilers may choose to provide additional feature. clang++ developers simply decided to keep it enabled. It is better to use -pedantic if we don't want those features.

Interestingly, while searching for related information I came upon C++ Support in Clang page where "Designated initializers" is listed as partially supported via extension for upcoming proposals:

experimental support for some proposed features of the C++ standard following C++17, provisionally named C++2a

This is the exact proposal for upcoming standard. So there might be designated initializers in future C++.

Why is C99 designated initializers not be supported by VC++ 2013 RC as promised?

Quote from the same page you linked:

Herb also announced that, in response to customer requests, the RTM version will also include a few tactical C99 language extensions when compiling C code, so that some popular community libraries (including FFmpeg) will now be able to compile with Visual C++ 2013.

So the designated initializers will be only in C code, not in C++ code. I see A is defined in C++ syntax, there :-)



Related Topics



Leave a reply



Submit