为什么我不能对具有成员初始值设定项列表的默认 ctor 使用 =default。



考虑以下类:

class Foo {
  int a, b;
public:
  Foo() : a{1}, b{2} {} // Default ctor with member initializer list
  //Foo() : a{1}, b{2} = default; // Does not work but why?
};

(编辑:因为它在几个答案中提到 - 我知道类内成员初始化器,但这不是这里的重点(

我认为第二个 ctor 定义会更优雅,更适合现代C++代码(如果您必须明确使用默认语义,另请参阅为什么您应该使用 =default(。但是,似乎没有通用编译器接受它。而cpp偏好对此保持沉默。

我的第一个想法是,成员初始值设定项列表以某种方式更改了链接的常见问题解答中所述的"默认语义",因为它可能会也可能不会默认构造成员。但是对于类内初始化项,我们会遇到同样的问题,只是这里的Foo() = default;工作得很好。

那么,为什么不允许呢?

= default;本身

就是一个完整的定义。它首先在语法上强制执行:

[dcl.fct.def.general]

1 函数定义具有以下形式

函数定义:    attribute-specifier-seq opt decl-specifier-seqopt declarator virt-specifier-seqopt function-body功能-主体:    ctor-initializeropt 复合语句    函数尝试块    = 默认值 ;    = 删除 ;

所以它要么是带有复合语句的成员初始值设定项列表,要么只是普通的= default;,没有大杂烩。

此外,= default意味着每个成员如何初始化的特定内容。这意味着我们明确希望像编译器提供的构造函数一样初始化所有内容。这与对构造函数的成员初始值设定项列表中的成员"执行特殊操作"相矛盾。

执行a{1}, b{2}意味着您不能再将其指定为 default 。 每个 [dcl.fct.def.default]/1 的默认函数定义为

函数体形式为 = default; 的函数定义称为显式默认定义。

如果我们检查 [dcl.fct.def.general]/1 中的函数体是什么,我们会看到它包含一个 ctor-initializer,它是一个 mem-initializer-list

这意味着,如果需要编译器提供的默认定义,则无法初始化成员。

解决此问题的方法是直接在类中指定默认值,然后将构造函数声明为默认值,例如

class Foo {
  int a{1}, b{2};
public:
  Foo() = default;
};

这并不能直接回答这个问题,但是 c++ 的"方式"是改用默认的成员初始值设定项,即

class Foo {
  int a = 1, b = 2;
public:
  Foo() = default; 
};

你使用的语法本身不再是默认的构造函数。

这是不允许的,因为根据定义,您尝试执行的操作意味着它不再是默认构造函数。无论如何,还有一种更优雅的方式来完成您想要的事情:

class Foo {
  int a {1};
  int b {2};
public:
  Foo() = default;
};

最新更新