当前位置: 首页 > 知识库问答 >
问题:

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

殳宸
2023-03-14

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

struct Baz
{
   Baz(int) {}
};

struct Foo
{
   int bar;
   Baz baz;
};

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

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

我的普通编译器(VS2012)将勉强接受这一点,但它提出了两个警告:

警告C4510:'Foo':无法生成默认构造函数。

警告C4610:结构“Foo”永远不能实例化-需要用户定义的构造函数

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

共有2个答案

段干恺
2023-03-14

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

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

孙翰墨
2023-03-14

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

[...] 如果类X没有用户声明的构造函数,则没有参数的构造函数将隐式声明为默认[…]在以下情况下,类X的默认默认构造函数被定义为已删除:

[...]

  • 任何潜在构造的子对象(具有大括号或相等初始值设定项的非静态数据成员除外)都具有类类型M(或其数组),并且M没有默认构造函数或重载解析(13.3),因为应用于M的默认构造函数会导致歧义或从默认默认构造函数中删除或无法访问的函数

[...]

Baz没有默认构造函数,因此上面强调的部分适用(emphasis mine)。

此类案件没有“未定义”或“格式错误”的地方。隐式声明的默认构造函数定义为deleted,仅此而已。你可以明确地做同样的事情,它仍然是有效的。

集料的定义在[8.5.1p1]中。对于C 14,它是:

聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有私有或受保护的非静态数据成员(第11条),没有基类(第10条),没有虚拟函数(10.3)。

“无用户提供”部分允许您对所有可能隐式声明的构造函数(使其成为用户声明的,但不是用户提供的)使用=删除,并且该类仍然是一个聚合,允许您对其使用聚合初始化。

至于警告C4610,我之前遇到过并报告过。正如你所见,它已经在即将到来的VC版本中修复。

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

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

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

当然,这只是一个例子,但我认为这是一个额外的迹象,表明这些案例没有错。

 类似资料:
  • 参加以下课程: 由于Foo(std::stringbar_, intbaz_=7);是我唯一的构造函数,编译器不应该为我实现默认构造函数,对吗?我认为我可以构造这个类的唯一两种方法是: 然而,为什么这是可能的? 当唯一的公共构造函数要求其第一个参数具有值时,我不理解如何默认构造类。将默认构造函数设为私有或尝试C 11删除它,没有什么区别。这是怎么发生的 http://ideone.com/CL7I

  • 问题内容: 我有一条记录,想要向其中添加默认构造函数。 但是它创建了带参数的构造函数。 我们如何向记录添加默认构造函数? 问题答案: 为了分裂头发,您永远无法定义默认构造函数,因为在没有定义构造函数的情况下,编译器会生成默认构造函数,因此根据定义,任何定义的构造函数都不是默认构造函数。 如果希望记录具有无参数构造函数,则记录确实允许添加额外的构造函数或工厂方法,只要调用将所有记录字段作为参数的“规

  • 似乎一个向量会检查move构造函数是否标记为noexcept,然后再决定重新分配时是移动还是复制元素。默认的移动构造函数是否定义为noexcept?我看到了以下文档,但它没有指定这一点。http://en.cppreference.com/w/cpp/language/move_constructor 隐式声明移动构造函数 如果没有为类类型(struct,类或联合),并且以下所有都是真的:没有用户

  • 问题内容: 默认构造函数到底是什么?你能告诉我以下哪个是默认构造函数,它与其他构造函数有何不同? 问题答案: 他们都不是。如果定义,则不是默认值。 除非你定义另一个构造函数,否则默认构造函数是自动生成的无参数构造函数。任何未初始化的字段都将设置为其默认值。对于你的榜样,它看起来像这样假设的类型String,int以及int,那类本身是公共的: 这与 完全没有构造函数。但是,如果定义至少一个构造函数

  • 我有一个记录,想添加默认构造函数。 但是它创建了带有参数的构造函数。 我们如何将默认构造函数添加到记录中?

  • 问题内容: 我知道我在这里问一些严重的101问题… 我有一些课,还有一个延伸课。在我有一个构造函数,它接受一组参数,并对其字段进行设置。派生类(例如)通常不需要进行修改。现在我的IDE给我 “ Foo中没有默认的构造函数” 。从一点点谷歌搜索,这似乎是因为“构造函数没有继承”。因此,一切都很好,但是我现在如何使它工作而不在每个派生类中复制此构造函数?我假设有一个更合理的方法? 问题答案: 使用构造