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

为什么自C++20以来,如果构造函数被显式默认或删除,聚合初始化就不再工作了?

赫连明诚
2023-03-14
struct Foo
{
    Foo() = default;
    int bar;
};
auto test = Foo { 0 };

(6):注意:任何构造函数都不能接受源类型,或者构造函数重载解析不明确

该项目使用/std:C++lates标志编译。我在Godbolt上复制了。如果我将它切换到/std:c++17,它的编译效果和以前一样好。

我试图用clang用-std=c++2a编译相同的代码,结果出现了类似的错误。此外,默认或删除其他构造函数也会生成此错误。

    null

但是,我在所有的项目中都显式地默认和删除了很多构造函数,因为我发现用这种方式使代码更有表现力是一个好习惯,因为与隐式默认或删除构造函数相比,它只会导致更少的意外。然而,随着这一变化,这似乎不再是一个好习惯了...

所以我的实际问题是:从C++17到C++20的变化背后的原因是什么?这种向后兼容性的破坏是故意的吗?是否有一些交易,比如“好吧,我们在这里打破了向下兼容,但这是为了更大的利益。”?这更大的好处是什么?

共有1个答案

令狐宏浚
2023-03-14

P1008的摘要,导致改变的提议:

C++目前允许一些具有用户声明构造函数的类型通过聚合初始化来初始化,绕过那些构造函数。结果是代码令人惊讶、混乱和有缺陷。本文提出了一个解决方案,使C++中的初始化语义更安全、更统一、更容易教授。我们还将讨论此修复带来的突破性变化。

他们举的一个例子如下。

struct X {
  int i{4};
  X() = default;
};

int main() {
  X x1(3); // ill-formed - no matching c’tor
  X x2{3}; // compiles!
}
 类似资料:
  • 主要内容:初始化 const 成员变量构造函数的一项重要功能是对成员变量进行初始化,为了达到这个目的,可以在构造函数的函数体中对成员变量一一赋值,还可以采用 初始化列表。 C++构造函数的初始化列表使得代码更加简洁,请看下面的例子: 运行结果: 小明的年龄是15,成绩是92.5 李华的年龄是16,成绩是96 如本例所示,定义构造函数时并没有在函数体中对成员变量一一赋值,其函数体为空(当然也可以有其他语句),而是在函数首部与函数体之间添

  • 如果我有一个struct Foo和一个struct Bar: 如果我初始化一个条并打印正确得到的值: 但是现在如果我声明这样的构造函数: 我失去了Bar::foo的默认构造,程序输出了32764 0 5! 为什么我不得不像这样无声地初始化每个成员变量: 只要我声明一个构造函数?在这种情况下,为什么默认构造不起作用?

  • 问题内容: 默认构造函数和直接初始化对象的字段之间有什么区别? 有什么原因要偏爱以下示例之一? 例子1 例子2 问题答案: 初始化程序在构造函数主体之前执行。(如果你同时具有初始化程序和构造函数,则会产生影响,构造函数代码将第二次执行并覆盖初始化值) 当你始终需要相同的初始值(例如,在你的示例中为给定大小的数组或特定值的整数)时,初始化器是很好的选择,但是它可以对你有利或不利于你: 如果你有许多构

  • 隐式默认构造函数有一个空主体和一个空初始值设定项列表(未定义的原始类型,默认构造函数用于用户定义的类型)。 这篇帖子说 确实进行了成员级值初始化,但在进行初始化时调用默认构造函数有什么意义 ? 是否调用隐式默认构造函数,以确保调用用户定义类型(可能具有非平凡的默认构造函数)的默认构造函数? 使现代化 似乎在调用编译器生成的隐式默认构造函数后,对象可能无法一致实例化,即未定义基元类型,并且用户定义的

  • 问题内容: 为什么我们必须在Servlets中重写init()方法,同时可以在构造函数中进行初始化,并让Web容器调用构造函数,同时在调用构造函数时将ServletConfig引用传递给Servlet? 当然,容器必须为此使用反射,但是容器仍然必须使用反射来调用简单的无参数构造函数 问题答案: 由于构造函数不能是接口的一部分,因此与常规方法不同,不能在Servlet API中“正式”指定构造函数。

  • 请帮我做这个程序: 这里,struct有一个私有析构函数,只是为了演示析构函数不是由编译器真正调用的,并简化代码的长度。 问题是: 如果不在此转换单元中编译,为什么要考虑字段默认初始化? 出现错误是因为为初始化字段创建了临时对象吗?(没有强制删除副本?) 那么和情况有什么不同?