C++中的聚合成员初始化14

J L*_*J L 3 c++ aggregate member-initialization c++14

有这个结构:

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;
};
Run Code Online (Sandbox Code Playgroud)

并声明:

A a = { { 1, 2, 3, 4 }, { 1 }, 5 };
Run Code Online (Sandbox Code Playgroud)

根据Clang(3.8.0)和GCC(5.4.0),这些是8种可能组合的值(a.b1.e和a.b2.a是重复的情况),关于初始值的位置从(或不),:

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 ?
Run Code Online (Sandbox Code Playgroud)

考虑到N3605和C++ 14标准(ISO/IEC 14882:2014)中的示例,第8.5.1节,第7段:

如果列表中的initializer-clause少于聚合中的成员,那么未明确初始化的每个成员都应从其brace-or-equal-initializer初始化,或者如果没有bra-or-equal-initializer,从空的初始化列表(8.5.4).

我假设案例010是正确的.那么,为什么情况011(a.b2.c)和001(a.b2.e)也不等于零?情况010为零,因为a.b2"确实具有初始化器",因此"忽略非静态数据成员初始化器"(再次为N3605).为什么不忽略默认成员初始值设定项?

事实上,阅读C++ 14标准引用它对我来说更有意义的情况是010将是12(它是零)并且情况011和001将是零(实际上是它们).所以我不明白为什么a.b2有时被认为是"有一个初始化器",有时则不是.

Tob*_*ght 6

声明a与初始化为它的所有成员:b1,b2x.这意味着我们就好像构建一样

a.b1 = B{ 1, 2, 3, 4 };
a.b2 = B{ 1 };
a.x = 5;
Run Code Online (Sandbox Code Playgroud)

B的定义说,B{ 1, 2, 3, 4 }手段B{ 1, 2, 3, 4, 23 }B{ 1 }手段B{ 1, 0, 22, 0, 23 }.而这正是你得到的结果.


如果你写过

A a = { { 1, 2, 3, 4 }, };
Run Code Online (Sandbox Code Playgroud)

然后a.b2将使用其默认值{11,12}进行初始化:

a.b1 = B{ 1, 2, 3, 4 };
a.b2 = B{ 11, 12 };
a.x = {};
Run Code Online (Sandbox Code Playgroud)

它可以帮助想那些括号表达式,如{ 1 }{ 11, 12 }在你的例子为完全构造的B对象,很久以前A的构造,甚至看到他们.