Why Are Designated Initializers Not Implemented in G++

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 is designated initialization accepted by gcc with no effect, and generated aggregate is somehow passed as arguments to class constructor

A class that has a user defined constructor is not an aggregate class. If designated initialiser is used, then the class shall be an aggregate. Your program uses designated initialiser on a non-aggregate, therefore it is an ill-formed program. Compilers are allowed to not compile it and are required to diagnose the issue.

Furthermore, a designated initialiser shall name a member of the aggregate. Your program doesn't name a member in the initialiser and therefore it is ill-formed.

Is it ISO C++20 or GNU C++ feature?

Designated initialisers in general are a standard C++20 feature, and are also a GNU feature prior to C++20.

Initialising non-aggregates with designated initialisers is not a standard C++ feature. Whether it is a bug or a feature, it is implementation specific thing.

Should state 1. be treated as gcc compiler silent bug?

Lack of diagnostic message is violation of the standard.

This seems to have been fixed in trunk and all cases using designated initialisers are an error in GCC: https://godbolt.org/z/TWKob6 The latest released version 10.2 still reproduces the lack of error.

non-trivial designated initializers not supported

This does not work with g++. You are essentially using C constructs with C++. Couple of ways to get around it.

1) Remove the "." and change "=" to ":" when initializing.

#include <iostream>

using namespace std;
struct ib_connection
{
int x;
};

struct ibv_device
{
int y;
};

struct app_data
{
int port;
int ib_port;
unsigned size;
int tx_depth;
int sockfd;
char *servername;
struct ib_connection local_connection;
struct ib_connection *remote_connection;
struct ibv_device *ib_dev;

};

int main()
{

struct app_data data =
{
port : 18515,
ib_port : 1,
size : 65536,
tx_depth : 100,
sockfd : -1,
servername : NULL,

local_connection : {5},
remote_connection : NULL,
ib_dev : NULL
};

cout << "Hello World" << endl;

return 0;
}

2) Use g++ -X c. (Not recommended) or put this code in extern C [Disclaimer, I have not tested this]

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.

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++.

Are non-trivial designated initializers going to be supported in the future (Post C++17)?

The proposal adopted to add designated initializers to C++20 (p0329r0) is limited, intentionally (Note that as an official language feature, it's specifically a C++20 feature - but gcc and clang have supported essentially this feature for a long time already):

Sample Image

C++ is a more complex language than C, and we have more things to worry about. So the rules we get are that you cannot mix designators and values, the designators appear in declaration order, are unique, and are neither nested nor array indices. This is already a very useful language feature, as-is.

If not, what is the biggest hindrance why it's not going to be supported

Motivation, probably. Do we really need that syntax? Is it a problem that needs solving? On the downside, there may be parsing ambiguities - you might be able to construct array index initializers that look a lot like lambdas. But if you think it's sufficiently worthwhile, you could write a proposal.

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

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.



Related Topics



Leave a reply



Submit