dlf*_*dlf 6 c++ default-constructor language-lawyer aggregate-initialization visual-studio-2012
可以定义struct(a)没有用户定义的构造函数,(b)不能生成默认构造函数.例如,Foo在下面:
struct Baz
{
Baz(int) {}
};
struct Foo
{
int bar;
Baz baz;
};
Run Code Online (Sandbox Code Playgroud)
您仍然可以创建Foo使用聚合初始化的实例:
Foo foo = { 0, Baz(0) };
Run Code Online (Sandbox Code Playgroud)
我的普通编译器(VS2012)会勉强接受这个,但它会引发2个警告:
警告C4510:'Foo':无法生成默认构造函数.
警告C4610:struct'Foo'永远不能被实例化 - 需要用户定义的构造函数
当然,我刚刚证明警告#2错误 - 你仍然可以使用聚合初始化来实例化它.我尝试过的在线编译器很高兴接受上述内容,因此我猜测VS2012只是过于激进了这个警告.但我想确定 - 这段代码是否正常,还是技术上违反了标准中一些不起眼的部分?
该标准明确允许类似Foo[12.1p4]中的情况:
\n\n\n[...] 如果类 X 没有用户声明的构造函数,则没有参数的构造函数将被隐式声明为默认构造函数 [...] 类 X 的默认构造函数被定义为已删除,如果:
\n\n[...]
\n\n\n
\n\n- 任何可能构造的子对象(带有大括号或等于初始化程序的非静态数据成员除外)都具有类类型 M (或其数组\n),并且M 没有默认构造函数或重载\n 解析(13.3):应用于 M\xe2\x80\x99s 默认构造函数会导致\n 歧义,或者导致函数被删除或无法从默认构造函数访问\n
\n[...]
\n
Baz没有默认构造函数,因此上面强调的部分适用(强调我的)。
这种情况不存在“未定义”或“格式错误”的情况。隐式声明的默认构造函数被定义为已删除,仅此而已。你可以明确地做同样的事情,它仍然是有效的。
\n\n聚合的定义在[8.5.1p1]中。对于 C++14,它是:
\n\n\n\n\n聚合是一个数组或类(第 9 条),没有用户提供的构造函数 (12.1),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),并且没有虚拟函数\n (10.3)。
\n
“无用户提供”部分允许您使用= delete可能隐式声明的所有构造函数(使它们由用户声明,但不是用户提供),并且该类仍然是一个聚合,允许您使用聚合对其进行初始化。
至于警告C4610,我以前遇到过并报告过。正如您所看到的,它已在即将发布的 VC++ 版本中得到修复。
\n\n可能值得一提的是,我在错误报告中使用的示例直接取自标准,它被视为格式良好([12.2p5.4]:
\n\nstruct S { int mi; const std::pair<int,int>& mp; };\nS a { 1, {2,3} };\nRun Code Online (Sandbox Code Playgroud)\n\n这与您的情况类似,但在这里,隐式声明的默认构造函数被定义为已删除,因为该类有一个没有初始值设定项的引用类型的非静态成员。
\n\n当然,这只是一个例子,但我认为这进一步表明这些案例没有任何问题。
\n