8

考虑以下类:

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)。但是,似乎没有常见的编译器接受它。而 cppreference 对此保持沉默。

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

那么,为什么不允许呢?

4

4 回答 4

11

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

[dcl.fct.def.general]

1函数定义的形式

功能定义:
    属性-说明符-seq opt decl-specifier-seq opt声明符 virt-specifier-seq opt function-body

功能体:
    ctor-initializer opt复合语句
    功能尝试块
    = 默认;
    =删除;

所以它要么是一个带有复合语句的成员初始化列表,要么只是简单= default;的,没有混搭。

此外,= default意味着有关如何初始化每个成员的特定内容。这意味着我们明确地希望像编译器提供的构造函数一样初始化所有内容。这与构造函数的成员初始化器列表中的成员“做一些特别的事情”相矛盾。

于 2019-06-05T12:43:58.503 回答
7

Doinga{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;

};
于 2019-06-05T12:51:15.170 回答
3

这并没有直接回答这个问题,但是 c++ 的“方式”是使用默认的成员初始化程序,它

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

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

于 2019-06-05T12:44:03.733 回答
2

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

class Foo {
  int a {1};
  int b {2};
public:
  Foo() = default;
};
于 2019-06-05T12:43:54.030 回答