当我编译以下代码的 #if 0
和 #if 1
版本时,如何解释差异:
#include <cstdlib>
struct A
{
explicit A() = default; // explicitly defaulted or deleted constructors are allowed for aggregates (since C++11)
#if 1
private :
#endif
int i;
};
int
main()
{
A a = {};
return EXIT_SUCCESS;
}
- for
#if 0
一切正常,编译成功。 - for
#if 1
编译失败并显示错误消息:error: chosen constructor is explicit in copy-initialization
表达式 A a = {};
取决于 A
是否聚合有什么区别?
最佳答案
TL;DR:Clang 和 GCC 拒绝您的代码是错误的。 CWG 1630无论选择的默认构造函数是 explicit
与否。
在 i
为 private
的代码变体中,A
不是聚合,因为它们不能有私有(private)成员。但是,只要 i
是 public
,A
就是一个聚合1,并且由于聚合,所以不会调用构造函数执行初始化(见蓝色框),所以你的构造函数是 explicit
是无关紧要的。
但是,一旦您引入私有(private)成员,您就需要按照红框进行值初始化。因此 [dcl.init]/(8.2) 适用:
[dcl.init]/(7.1) 为这种情况定义了默认初始化:
§13.3.1.3 给出了
For […] default-initialization, the candidate functions are all the constructors of the class of the object being initialized.
在任何时候都不会考虑原始上下文 - 复制或直接初始化。 (§13.3.1.7 也不适用。)事实上,这是有意的;见 CWG #1518 :
This issue is resolved by the resolution of issue 1630: default initialization now uses 13.3.1.3 [over.match.ctor], which now permits explicit constructors for default-initialization.
Clang 和 GCC(和 VC++)还没有实现相应的 DR,因此拒绝 C++14 模式下的代码是不正确的。
1) 您的类有一个用户声明的构造函数,但它不是用户提供,即不妨碍您的类成为一个聚合。记忆一下 [dcl.init.aggr]/1 中的定义:
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
关于c++ - 显式默认的默认构造函数和聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33522985/