可以定义没有用户定义构造函数的struct
(a),以及(b)无法生成默认构造函数的Foo
(a)。例如,下面的struct Baz
{
Baz(int) {}
};
struct Foo
{
int bar;
Baz baz;
};
:
Foo
您仍然可以使用聚合初始化创建Foo foo = { 0, Baz(0) };
的实例:
{{1}}
我的普通编译器(VS2012)会勉强接受这个,但它会引发2次警告:
警告C4510:' Foo':无法生成默认构造函数。
警告C4610:struct' Foo'永远不能实例化 - 需要用户定义的构造函数
当然,我刚刚证明警告#2错误 - 您仍然可以使用聚合初始化来实例化它。我尝试过的在线编译器很高兴能够接受上述内容,所以我猜测VS2012只是过于激进了这个警告。但我想确定 - 这段代码是否正常,还是技术上违反了标准中一些不起眼的部分?
答案 0 :(得分:2)
该标准明确允许[12.1p4]中的Foo
等案例:
[...]如果没有用户声明的构造函数 类X,没有参数的构造函数被隐式声明为默认值[...]类X的默认默认构造函数定义为 删除如果:
[...]
- 除了具有大括号或等于初始值的非静态数据成员之外,任何可能构造的子对象都具有类类型M(或数组) 并且 M没有默认构造函数或重载 应用于M的默认构造函数的分辨率(13.3)导致a 歧义或在被删除或无法访问的函数中 默认默认构造函数
[...]
Baz
没有默认构造函数,因此上面强调的部分适用(强调我的)。
对于此类案件,没有任何“未定义”或“形成不良”。隐式声明的默认构造函数被定义为已删除,即全部。你可以明确地做同样的事情,它仍然是有效的。
聚合的定义见[8.5.1p1]。对于C ++ 14,它是:
聚合是一个没有用户提供的数组或类(第9条) 构造函数(12.1),没有私有或受保护的非静态数据成员 (第11条),没有基类(第10条),也没有虚函数 (10.3)。
'无用户提供'部分允许您对可能被隐式声明的所有构造函数使用= delete
(使用户声明但不是用户提供),并且该类仍然是聚合,允许你在它上面使用聚合初始化。
至于警告C4610,我在我和reported it面前遇到过它。正如您所看到的,它已在即将推出的VC ++版本中得到修复。
值得一提的是,我在错误报告中使用的示例直接来自标准,在那里它被视为格式良好([12.2p5.4]:
struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };
这与您的情况类似,但是在这里,隐式声明的默认构造函数被定义为已删除,因为该类具有不具有初始值设定项的非静态引用类型成员。
当然,这只是一个例子,但我认为这是一个额外的迹象表明这些案件没有任何问题。
答案 1 :(得分:-1)
这实际上不是聚合初始化,它是统一的,只是最近才得到VS的支持。这个警告只是他们没有正确更新它以反映该类型现在可以统一初始化。
聚合可能没有用户定义的非默认非删除构造函数,而聚合UDT的规则是每个成员也必须是聚合。因此,Baz不是聚合体,也不是直接结果,也不是Foo。