Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aggregate Member Initialization in C++14

Having this structure:

struct A {
    struct B {
        int a = 21;
        int b;
        int c = 22;
        int d;
        int e = 23;
    };
    B b1  = { 11, 12 };
    B b2  = { 11, 12, 13 };
    int x;
};

And declaring:

A a = { { 1, 2, 3, 4 }, { 1 }, 5 };

According to both Clang (3.8.0) and GCC (5.4.0), these are the values of the 8 possible combinations (a.b1.e and a.b2.a are repeated cases), regarding where the initial value is taken from (or not), :

a.b1.a = 1   // 111
a.b1.b = 2   // 110
a.b1.c = 3   // 101
a.b1.d = 4   // 100
a.b2.b = 0   // 010    // Why not 12 instead of  0? -> Explained in N3605
a.b2.c = 22  // 011    // Why not  0 instead of 22 ?  Why not 13 ?
a.b2.d = 0   // 000
a.b2.e = 23  // 001    // Why not  0 instead of 23 ?

Taking into account the example in N3605 and the C++14 Standard (ISO/IEC 14882:2014), Section 8.5.1, Paragraph 7:

If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from its brace-or-equal-initializer or, if there is no brace-or-equal-initializer, from an empty initializer list (8.5.4).

I assume case 010 is correct. Then, why cases 011 (a.b2.c) and 001 (a.b2.e) are not also equal to zero? Case 010 is zero because a.b2 "does have an initializer", therefore "the non-static data member initializer is ignored" (N3605 again). Why the default member initializers are not ignored as well?

In fact, reading the C++14 Standard quote it would make more sense to me that case 010 would be 12 (it is zero) and cases 011 and 001 would be zero (as they actually are). So what I don't understand is why a.b2 is sometimes considered to "have an initializer" and other times it is not.

like image 718
J L Avatar asked Jul 15 '26 06:07

J L


1 Answers

You declare a with initializers for all its members: b1, b2 and x. That means we construct as if

a.b1 = B{ 1, 2, 3, 4 };
a.b2 = B{ 1 };
a.x = 5;

B's definition says that B{ 1, 2, 3, 4 } means B{ 1, 2, 3, 4, 23 } and that B{ 1 } means B{ 1, 0, 22, 0, 23 }. And that's exactly the result you get.


If you had written

A a = { { 1, 2, 3, 4 }, };

then a.b2 would have been initialized using its default of { 11, 12 }:

a.b1 = B{ 1, 2, 3, 4 };
a.b2 = B{ 11, 12 };
a.x = {};

It may help to think of those brace-expressions such as { 1 } and { 11, 12 } in your example as being fully-constructed B objects, long before A's constructor even sees them.

like image 91
Toby Speight Avatar answered Jul 25 '26 11:07

Toby Speight



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!