请查看此代码
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;
?
答案 0 :(得分:50)
默认构造函数是 suppressed ,因为有一些常量成员需要显式初始化。
因此,由于这种抑制,编写Bond() = default
不会不重新引入默认构造函数。
(您可以通过删除类中的所有构造函数来看到此效果-您仍然无法实例化b
。)
如果您从成员中删除const
,那么一切都会好起来的;尽管另一种选择是为每个const
成员提供一个
brace-or-equal-initializer ;
const int payments_per_year = 2;
const int period_length_in_months = 6;
例如。
答案 1 :(得分:25)
您正受到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;
^
...
答案 2 :(得分:24)
另一种解决方法是在常量的声明中指定默认值:
const int payments_per_year = {12};
这仍然可以被有价值的构造函数覆盖,但是允许默认的构造函数继续进行。
这也是简化多个构造函数案例的非常灵活的方法。