【问题标题】:Why doesn't my compiler recognise "Bond() = default;"?为什么我的编译器无法识别“Bond() = default;”?
【发布时间】:2019-04-12 23:40:48
【问题描述】:

请看这段代码

class Bond
{
    public:
        Bond(int payments_per_year, int period_lengths_in_months);
        Bond() = default;

    private:
        const int payments_per_year;
        const int period_length_in_months;
    };

int main()
{
    Bond b; // Error here
}

尝试编译时出现错误:

错误 C2280:“Bond::Bond(void)”:试图引用已删除的函数”。

这不是违反“3 规则”,因为我已经添加了默认构造函数。

为什么编译器不能识别Bond() = default;

【问题讨论】:

  • 我还有其他错误uninitialized const member in 'const int'。当您初始化常量成员时,不会再产生错误。
  • 违反三规则与问题完全无关,无论是否存在(默认)构造函数。
  • = default一个特殊的成员并不意味着它存在,而是隐含的产生了。如果隐式生成的不存在,那么你得到这个。
  • 尽管我们很可能从本例中引用的错误中识别出编译器,但任何与“为什么我的编译器”相关的问题都将从指示 which 编译器中受益匪浅,并且哪个版本。

标签: c++ c++11


【解决方案1】:

默认构造函数是被抑制的,因为有需要显式初始化的常量成员。

因此,由于这种抑制,写入 Bond() = default 并不会重新引入默认构造函数。

(您可以通过删除类中的所有构造函数来看到这种效果 - 您仍然无法实例化 b。)

如果您从成员中删除const,那么一切都会好起来的;尽管另一种选择是为每个 const 成员提供一个 brace-or-equal-initializer

const int payments_per_year = 2;
const int period_length_in_months = 6;

例如。

【讨论】:

    【解决方案2】:

    C++ 标准草案中的 [class.default.ctor]p2 部分(或 C++11 中的 [class.ctor]p5)会影响您,该部分表示:

    如果满足以下条件,则将类 X 的默认默认构造函数定义为已删除:
    ...
    - 任何没有大括号或相等初始化器的 const 限定类型(或其数组)的非变体非静态数据成员都没有用户提供的默认构造函数,
    ...

    他们可能解决您的问题的关键是使用短语没有大括号或相等初始化器,因此如果您提供 大括号或相等初始化器解决您的问题,例如:

    const int payments_per_year{12};
    const int period_length_in_months{48};
    

    brace-or-equal-initializer 不需要大括号,我们可以看看这个语法:

    brace-or-equal-initializer:
        = initializer-clause
        braced-init-list
    

    但使用统一初始化有一些优点,例如使narrowing conversions ill-formed值得习惯使用它们。

    gcc 和 clang 都为此 see the live godbolt session 提供了更有意义的诊断。有时在多个编译器上尝试你的代码会很有帮助,特别是如果你有一个像这样的最小测试用例,例如叮当说:

     warning: explicitly defaulted default constructor is implicitly deleted [-Wdefaulted-function-deleted]
        Bond() = default;
        ^
     note: default constructor of 'Bond' is implicitly deleted because field 'payments_per_year' of const-qualified type 'const int' would not be initialized
        const int payments_per_year;
                  ^
    ...
    

    【讨论】:

    【解决方案3】:

    另一个解决方法是在常量的声明中指定一个默认值:

    const int payments_per_year = {12};
    

    这仍然可以被有值构造函数覆盖,但允许默认构造函数继续。

    这也是一种非常灵活的方式来简化您的多个构造函数案例。

    【讨论】:

    • 我们需要牙套吗?
    • 等于 and 大括号肯定很奇怪。不确定它的实际含义。从 initializer_list 初始化?无论如何:类内成员初始化器是——好吧——初始化器,并且初始化的语法规则适用。这意味着 = 或 {}。
    • @PaulSanders 不,您不需要大括号,但统一初始化有很多优点,例如使缩小转换格式不正确,值得习惯使用它们。请参阅下面的更新。
    • @ShafikYaghmour:你可以保留大括号并放弃相等。
    • @ShafikYaghmour:是的,这就是我更喜欢你的答案的部分原因(另一个是实际的标准引号)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-14
    • 2019-03-20
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多