C++ 为什么';“我的编译器不承认”;债券()=违约&引用;?

C++ 为什么';“我的编译器不承认”;债券()=违约&引用;?,c++,c++11,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

请看这个代码

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;

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

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

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

如果您从成员中删除
常量
,则一切都会好起来;尽管另一种选择是为每个
常量
成员提供一个大括号或相等的初始值设定项

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

例如。

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

const int payments_per_year = {12};
这仍然可以被值构造函数覆盖,但允许默认构造函数继续


<>这也是一个非常灵活的方法来简化多个构造函数的例子。

< P>你受到C++标准草案(或C++ 11)的部分的影响,它表示:

如果:

-没有大括号或相等初始值设定项的const限定类型(或其数组)的任何非变量非静态数据成员都没有用户提供的默认构造函数,

解决问题的关键可能是短语不带大括号或相等的初始值设定项,因此,如果您提供大括号或相等的初始值设定项来解决问题,例如:

const int payments_per_year{12};
const int period_length_in_months{48};
不需要大括号,我们可以在语法中看到:

brace-or-equal-initializer:
    = initializer-clause
    braced-init-list
但是使用统一初始化有一些优点,比如使它值得使用它们

gcc和clang都为此提供了更有意义的诊断。有时在多个编译器上尝试您的代码会很有帮助,特别是如果您有这样一个最小的测试用例,例如,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;
              ^
...

“const int”中还有一个错误
未初始化const成员。
初始化常量成员时,不会再产生错误。三违反规则与问题无关,不管是否存在(默认值)构造函数。
=默认值
ing一个特殊成员并不意味着它存在,而是意味着隐式成员已生成。如果隐式生成的成员不存在,则您将得到此结果。即使我们很可能从本例中引用的错误中识别编译器,但有任何问题“为什么我的编译器?”“指出哪个编译器以及它的哪个版本将大大受益。可能值得提交一份错误报告,但诊断可能更有意义。一些[统一初始化捕获最近出现的错误]示例(我们需要大括号吗?等于和大括号确实很奇怪。不确定它的实际含义。初始化器列表中的Init?无论如何:类内成员初始化器是–嗯–初始化器,初始化的语法规则适用。这意味着=或{}@PaulSanders不,您不需要大括号,但统一初始化有很多优点,例如使窄化转换格式错误,值得使用。请参阅下面的更新。@ShafikYaghmour:您可以保留大括号,但删除相等的大括号。@ShafikYaghmour:是的,这也是我更喜欢使用a的部分原因nswer(另一个是实际的标准报价)。