这看起来像一个简单的错字,但情况很复杂,可以逐步解决。
首先让我展示一下似乎可行的解决方案:
int main()
{
str t[2] = { { { {0, 2}, {4, 6} } }, { { {1, 3}, {5, 7} } } };
cout << t[1].t[0].t[1] << t[0].t[1].t[0] << endl;
return 0;
}
所以我们有一个str 数组,其中包含一个sct 数组。
让我们从后者开始。你初始化一个 sct 数组,如下所示:
sct x[2] = { {0, 1}, {2, 3} };
现在,您可以使用 str 的单个实例
str y = { { {0, 2}, {4, 6} } };
str t[2] 剩下的就是在大括号内安排两个 str 初始化表达式的副本:
str t[2] = { { { {0, 2}, {4, 6} } }, { { {1, 3}, {5, 7} } } };
已编辑:在第一次阅读时,我误解了这个问题。帖子更新后,很明显问题是为什么可以去掉两对大括号,但只去掉一对会导致语法错误。
要了解解析器如何解释代码,您可能需要查看解析树。您可以使用 -fdump-tree-... 选项在解析器的多个阶段制作 gcc 转储树。这里-fdump-tree-original 可能有用。
为避免额外的混淆,让我们确保结构的元素具有不同的名称:
struct sct
{
int a[2];
};
struct str
{
sct b[2];
};
这是我使用 GCC 7.5 从
得到的输出
>>>> CODE:
str t[2] = { { 0, 2, 4, 6 }, { 1, 3, 5, 7 } };
>>>> tree enabled by -tree-original
struct str t[2] = {{.b={{.a={0, 2}}, {.a={4, 6}}}}, {.b={{.a={1, 3}}, {.a={5, 7}}}}};
您可以看到编译器在每个结构的初始化表达式和每个命名字段的初始化表达式周围添加了隐式括号。
现在考虑编译失败的表达式:
str t[2] = { { {0, 2},{4, 6} }, { {1, 3},{5, 7} } };
此表达式的树的上层是
/*Step 1: */ struct str t[2] = { {.b={0, 2}, {4, 6} }, {.b={1, 3}, {5, 7} } };
但由于 b 是 sct 的数组,我们尝试使用 {0,2} 获取来初始化它
sct b[2] = {0, 2};
这扩展为
struct sct b[2] = {{.a={0, 2} }};
这是有效的 C++,因为数组的第一个元素是显式初始化的,而第二个元素是用零隐式初始化的。
有了这些知识,我们得到以下树
/*Step 2: */ struct str t[2] = { {.b={{.a={0, 2} }}, {4, 6} }, {.b={{.a={1, 3} }}, {5, 7} } };
现在我们剩下以下内容:
struct str z = { { { {0,2} }, { {0,0} } }, {4, 6} };
而编译器理所当然地抱怨:
error: too many initializers for ‘str’
作为最后的检查考虑以下声明
struct sxc
{
sct b[2];
int c[2];
}
struct sxc z = { {0,2} , {4, 6} };
这将编译并产生以下结构:
{ .b = { { .a={0,2} }, { .a={0,0} } }, .c={4, 6} }