缺少用户定义的构造函数是否违反了非默认可构造结构的标准?

Does it violate the standard for a non-default-constuctible struct to lack a user-defined constructor?

可以定义 struct (a) 没有用户定义的构造函数,以及 (b) 无法为其生成默认构造函数。例如下面的Foo

struct Baz
{
   Baz(int) {}
};

struct Foo
{
   int bar;
   Baz baz;
};

您仍然可以使用聚合初始化创建 Foo 的实例:

Foo foo = { 0, Baz(0) };

我的普通编译器 (VS2012) 会勉强接受这个,但它会引发 2 个警告:

warning C4510: 'Foo': default constructor could not be generated.

warning C4610: struct 'Foo' can never be instantiated - user defined constructor required

当然,我刚刚证明警告 #2 是错误的——您仍然可以使用聚合初始化来实例化它。我试过的在线编译器很乐意接受上述内容,所以我猜 VS2012 只是对这个警告过于激进。但我想确定——这段代码是否正确,或者它在技术上是否违反了标准的某些模糊部分?

这实际上不是聚合初始化,它是统一的,最近才被 VS 支持。这个警告只是他们没有正确更新它以反映该类型现在可以统一初始化。

聚合不能有用户定义的非默认非删除构造函数,聚合UDT的规则是每个成员也必须是一个聚合。因此,Baz 不是聚合,作为直接结果,Foo 也不是。

标准明确允许[12.1p4]中的Foo这样的情况:

[...] If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared as defaulted [...] A defaulted default constructor for class X is defined as deleted if:

[...]

  • any potentially constructed subobject, except for a non-static data member with a brace-or-equal-initializer, has class type M (or array thereof) and either M has no default constructor or overload resolution (13.3) as applied to M’s default constructor results in an ambiguity or in a function that is deleted or inaccessible from the defaulted default constructor

[...]

Baz 没有默认构造函数,所以上面强调的部分适用(强调我的)。

'undefined' 或 'ill-formed' 没有关于此类情况的任何内容。隐式声明的默认构造函数被定义为已删除,仅此而已。你可以明确地做同样的事情,它仍然有效。

聚合的定义在 [8.5.1p1] 中。对于 C++14,它是:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

'no user-provided' 部分允许您在所有可能隐式声明的构造函数上使用 = delete(使它们由用户声明,但不是用户提供)和 class仍然是一个聚合,允许您对其使用聚合初始化。

关于警告C4610,我自己和reported it之前都遇到过。如您所见,它已在即将发布的 VC++ 版本中修复。

可能值得一提的是,我在错误报告中使用的示例直接取自标准,在标准中被视为格式正确 ([12.2p5.4]:

struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };

这与您的情况类似,但在这里,隐式声明的默认构造函数被定义为已删除,因为 class 具有引用类型的非静态成员,该成员没有初始化程序。

当然,这只是一个例子,但我认为这进一步表明这些案例没有任何问题。