3

有这个结构:

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;
};

并声明:

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

根据 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 ?

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

如果列表中的初始化子句少于聚合中的成员,则每个未显式初始化的成员都应从其大括号或相等初始化器初始化,或者,如果没有大括号或相等初始化器,从一个空的初始化列表(8.5.4)。

我认为案例 010 是正确的。那么,为什么情况011(a.b2.c)和001(a.b2.e)也不等于0呢?情况 010 为零,因为 a.b2 “确实有一个初始化程序”,因此“忽略了非静态数据成员初始化程序”(再次N3605)。为什么默认成员初始化器也不会被忽略?

事实上,阅读 C++14 标准引用对我来说更有意义的是,案例 010 将是 12(它为零),而案例 011 和 001 将是零(实际上是)。所以我不明白为什么 a.b2 有时被认为是“有一个初始化程序”,而其他时候却不是。

4

2 回答 2

6

a用初始化器声明它的所有成员b1b2x。这意味着我们构建好像

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

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 }, };

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

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

将这些大括号表达式(例如{ 1 }{ 11, 12 }在您的示例中)视为完全构造的B对象可能会有所帮助,早在A构造函数甚至看到它们之前。

于 2017-01-10T17:19:31.870 回答
2

在此示例{1, 2, 3, 4}中是B b1. 编译器已经有一个初始化器,所以现在它不会再看{ 11, 12 }了。

于 2017-01-10T17:00:07.610 回答