给定的程序是不规范的原因如下所述。
C++20
B
is an 总计的。既然你是not显式初始化a
, dcl.init.aggr#5 https://timsong-cpp.github.io/cppwp/n4861/dcl.init.aggr#5适用:
- 对于非联合聚合,每个不是显式初始化元素的元素都按如下方式初始化:
5.2 否则,如果该元素不是引用,则该元素是从空初始化器列表复制初始化([dcl.init.list])。
这意味着a
is 复制已初始化来自空的初始值设定项列表。换句话说,就好像我们在写:
A a = {}; // not valid see reason below
另请注意,复制初始化上下文中的列表初始化称为复制列表初始化这里就是这种情况。并从超过.match.list#1.2 https://timsong-cpp.github.io/cppwp/n4861/over.match.list#1.2:
在复制列表初始化中,如果选择显式构造函数,则初始化为不规范的.
归根结底,失败的原因在于A a = {};
格式不正确。
C++11
Since B
是一个聚合,并且列表中的初始化子句少于聚合中的成员,并且来自聚合初始化文档 https://en.cppreference.com/w/cpp/language/aggregate_initialization:
聚合初始化的效果是:
- 如果初始值设定项子句的数量小于成员和基数 (C++17 起) 的数量或初始值设定项列表完全为空,则剩余的成员和基数 (C++17 起) 将由其默认成员初始值设定项进行初始化,如果在类定义中提供,否则 (C++14 起)从空列表复制初始化,按照通常的列表初始化规则(使用默认构造函数对非类类型和非聚合类执行值初始化,并对聚合执行聚合初始化)。
这再次意味着a
is 复制已初始化从空列表中{}
。也就是说,就好像我们在写:
A a = {}; // not valid see reason below
但从过度匹配函数 https://timsong-cpp.github.io/cppwp/n3337/over.match.funcs:
在复制列表初始化中,如果选择显式构造函数,则初始化为不规范的.
所以我们再次面临同样的问题,即A a = {};
无效。
Solution
为了解决这个问题,我们可以通过A{}
or A{0}
作为列表内的初始值设定项,如下所示:
B b = { A{} }; //ok now
B c = { A{0} }; //also ok
工作演示 https://godbolt.org/z/b6G4hve48.
Note
注意写A a{};
另一方面是格式良好的,因为这是一个直接初始化上下文,所以它是直接列表初始化.