gpt4 book ai didi

c++ - 子聚合的指定初始值设定项是否需要花括号?

转载 作者:行者123 更新时间:2023-12-04 04:30:13 26 4
gpt4 key购买 nike

在下面的程序中,聚合结构体 B有字段a ,它本身就是一个集合。可以使用 C++20 指定初始值设定项设置其值而不用花括号括起来吗?

struct A { int i; };
struct B { A a; };

int main() {
[[maybe_unused]] B x{1}; //ok everywhere
[[maybe_unused]] B y{.a = {1}}; //ok everywhere
[[maybe_unused]] B z{.a = 1}; //ok in MSVC,Clang; error in GCC
}
MSVC 和 Clang 编译器接受此代码。但是 GCC 发出了一个奇怪的错误:
error: 'A' has no non-static data member named 'a'
演示: https://gcc.godbolt.org/z/65j1sTcPG
是 GCC 中的错误,还是标准不允许这种初始化?

最佳答案

TLDR; GCC 是对的,其他人都错了,因为他们假装指定的初始化列表一直表现得像等效的非指定初始化列表。

要了解这里发生了什么(以及为什么编译器不同意),让我们看一下您的第一个示例:

B x{1};
由于我们使用大括号, rules of list initialization kick in .该列表不是指定的初始化列表,因此 3.1 失败。 3.2 失败,因为 int不是类型 B或派生自 B 的类型. 3.3 失败失败,因为 B不是字符数组。最后是 3.4,这将我们带到 aggregate initialization .
[dcl.init.aggr]/3.2 tells us B 的显式初始化元素由 B::a 组成.
第 4 段告诉我们如何初始化显式初始化的元素。 4.1 不适用,如 B不是 union .但也... 4.2 不适用,因为 B::a不能从 1 复制初始化.
这似乎不应该起作用。幸运的是, paragraphs 15 and 16 exist :

Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the elements of a subaggregate; it is erroneous for there to be more initializer-clauses than elements. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the elements of the subaggregate; any remaining initializer-clauses are left to initialize the next element of the aggregate of which the current subaggregate is an element.

All implicit type conversions ([conv]) are considered when initializing the element with an assignment-expression.If the assignment-expression can initialize an element, the element is initialized. Otherwise, if the element is itself a subaggregate, brace elision is assumed and the assignment-expression is considered for the initialization of the first element of the subaggregate.


也就是说,如果初始化程序无法初始化 A通过复制初始化,大括号省略规则开始生效。和 A可以从 {1} 的初始化列表中初始化.因此它是。
这就是指定初始值设定项有问题的地方。一个 designated-initializer-list不是 initializer-list .因此,大括号省略段落不适用。
因此, B z{.a = 1};必须失败。
其他编译器没有捕捉到这一点的原因可能如下。他们可能通过去除指定并在非连续元素之间插入任何默认成员初始值设定项/值初始化,然后应用正常聚合初始值设定项规则来实现指定初始值设定项。但这并不完全相同,因为指定的初始值设定项列表不参与大括号省略。

关于c++ - 子聚合的指定初始值设定项是否需要花括号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68687304/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com