为什么我的编译器不识别"Bond()= default;"?

Sas*_*ram 39 c++ c++11

请看这个代码

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
}
Run Code Online (Sandbox Code Playgroud)

在尝试编译时,我收到一个错误:

错误C2280:'Bond :: Bond(void)':尝试引用已删除的函数".

因为我已经添加了默认构造函数,所以这不是"3规则"违规.

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

Bat*_*eba 50

由于存在需要显式初始化的常量成员,因此将禁止默认构造函数.

因此,由于该抑制,写作Bond() = default没有重新引入默认的构造函数.

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

如果你const从成员中撤下,那么一切都会顺利; 虽然另一种选择是为每个成员提供支撑或平等初始化器const ;

const int payments_per_year = 2;
const int period_length_in_months = 6;
Run Code Online (Sandbox Code Playgroud)

例如.


Sha*_*our 25

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

如果出现以下情况,则将类X的默认默认构造函数定义为已删除:
...
- 任何const-qualified类型(或其数组)的非变量非静态数据成员,没有大括号或等于初始化程序的用户没有用户- 提供默认构造函数,
...

他们可能解决问题的关键是使用没有大括号或等号初始化程序的短语,所以如果你提供的大括号或者等于初始化程序将解决你的问题,例如:

const int payments_per_year{12};
const int period_length_in_months{48};
Run Code Online (Sandbox Code Playgroud)

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

brace-or-equal-initializer:
    = initializer-clause
    braced-init-list
Run Code Online (Sandbox Code Playgroud)

但是使用统一初始化有一些优点,例如缩小转换格式不正确,值得习惯使用它们.

gcc和clang都为此提供了更有意义的诊断,请参阅实时godbolt会话.有时在多个编译器上尝试代码会很有帮助,特别是如果你有一个像这样的最小测试用例,例如clang说:

 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;
              ^
...
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的详细解答. (2认同)

Gem*_*lor 24

另一个修复方法是在常量声明中指定一个默认值:

const int payments_per_year = {12};
Run Code Online (Sandbox Code Playgroud)

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

这也是一种非常灵活的简化多个构造函数的方法.

  • @PaulSanders不,你不需要大括号,但统一初始化有很多优点,例如缩小转换格式错误,值得习惯使用它们.请参阅下面的更新. (6认同)
  • @ShafikYaghmour:你可以保持大括号并放弃平等. (4认同)
  • 等于*和*括号绝对是奇怪的.不确定它实际意味着什么.从initializer_list初始化?无论如何:类内成员初始化器是 - well - 初始化器,并且初始化的语法规则适用.这意味着=或{}. (2认同)