为什么我不能对具有成员初始值设定项列表的默认 ctor 使用 =default。
Why can't I use =default for default ctors with a member initializer list
考虑以下类:
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;
};
- 默认参数和空列表初始化
- C++11 默认类成员初始化与初始值设定项列表同时
- 当 T 不可默认构造时,构造函数初始值设定项列表中 std::array<T,N> 的初始化
- 带有默认类的模板参数列表
- 如何将用户下载的标头文件添加到系统中默认情况下的标题文件列表
- 作为参数的空初始值设定项列表不调用默认构造函数
- 为什么我不能对具有成员初始值设定项列表的默认 ctor 使用 =default。
- swig-包装到c#时,没有默认的std ::列表,我该怎么做
- 用默认参数值和空参数列表区分构造函数
- 初始化类成员 - 默认值还是成员初始化列表?
- 如果有默认成员初始化,为什么要使用成员初始化列表
- C - 混合默认成员初始化器和成员初始化列表 - 坏主意
- 带有模板的链接列表:调用到隐式删除的默认构造函数
- C++构造函数初始化列表调用默认构造函数.为什么
- 为什么默认成员值禁止使用支持列表初始化
- 具有默认构造函数的对象的初始化列表
- 是在默认构造函数之前或之后调用的初始化列表
- 启用默认初始值设定项列表构造函数
- 如何将列表语法与默认精神一起使用
- 当用户将列表视图项拖动到其滚动条上时,执行默认滚动行为