C++ C++;11个已删除/默认构造函数

C++ C++;11个已删除/默认构造函数,c++,list-initialization,deleted-functions,defaulted-functions,C++,List Initialization,Deleted Functions,Defaulted Functions,我对C++11和C++17中如何/为什么调用构造函数有点困惑 #include <iostream> using namespace std; //--- template<typename T> struct StructTest { public: const T Var = -1; //--- // constexpr StructTest() = delete; // 1 // constexpr StructTest() = defau

我对C++11和C++17中如何/为什么调用构造函数有点困惑

#include <iostream>
using namespace std;

//---

template<typename T>
struct StructTest
{
public:
  const T Var = -1;

  //---

  // constexpr StructTest() = delete;  // 1
  // constexpr StructTest() = default; // 2

  // constexpr StructTest(const StructTest &Source) = delete;                  // 3
  // constexpr StructTest(const StructTest &Source) = default;                 // 4
  // constexpr StructTest(const StructTest &Source) {cout << "Copy" << endl;}; // 5
};

//---

StructTest<int> A{};
StructTest<int> A1{1};
StructTest<int> A2(A);

//---

int main(void)
{
  return(0);
};
#包括
使用名称空间std;
//---
模板
结构测试
{
公众:
常数T Var=-1;
//---
//constexpr StructTest()=删除;//1
//constexpr StructTest()=默认值;//2
//constexpr StructTest(const StructTest&Source)=删除;//3
//constexpr StructTest(const StructTest&Source)=默认值;//4
//constexpr StructTest(const StructTest&Source){cout
1,编译A和A1的.List init,以及A2的默认复制构造函数

在本例中,您之所以调用List init,实际上是因为
StructTest
是一个聚合。这是允许的,因为存在显式默认或删除的构造函数仍然使类成为聚合

2,编译A和list init A1?的默认构造函数,以及A2的默认副本构造函数

A1
初始化为聚合,与1中发生的情况类似。其余部分正确

1+3或2+3,无法编译,因为A2的复制构造函数已删除

这是预期的行为,因为复制构造函数被标记为已删除

1+4,编译A和list init A1?的默认构造函数,以及A2的默认副本构造函数

同样,为
A
A1

2+4,编译A和list init A1?的默认构造函数,以及A2的默认副本构造函数

A
A1
将被聚合初始化,但在初始化
A
时,它将使用默认的成员初始值设定项
Var

1+5,编译失败。表示A缺少(删除)默认构造函数,并且A1没有匹配的构造函数

5是用户提供的非默认或已删除的构造函数。这意味着
StructTest
不再是聚合,您无法再聚合并初始化它

2+5,未能编译。A1是否没有匹配的构造函数


与1+5

的原因相同,您称之为
list init
的实际上被称为聚合初始化。您的类在所有情况下都是聚合的,但当您取消注释第5行时,它就不再是聚合了。聚合类是一个所有构造函数都默认(显式或隐式)的类或已删除。您只有一个非默认的、未删除的构造函数,因此除非您取消对其的注释,否则您的类仍然是一个聚合

考虑到这一点,大多数示例都围绕聚合初始化展开,除非您通过删除复制构造函数或添加非默认的复制构造函数来明确禁止复制,并使类成为非聚合类

有关聚合和聚合初始化的更多信息:

(这是其他答案的附加信息)

由于聚合定义的变化,C++11、C++14/17和C++20!的代码行为有所不同

在C++11中,该类不是聚合,因为它有一个大括号或相等的初始值设定项(
=-1
),所以案例1不会编译

在C++14和17中,类是一个聚合,其他答案涵盖了这种情况


在C++20中,该类不会再次成为聚合,因为有一条新规则,即任何用户声明的构造函数都会取消类成为聚合的资格;因此,案例1将再次停止编译,而在案例2中,
structTestA1{1}由于构造函数的参数太多等原因,
将无法编译。

我看不出1是如何编译的。
structTesta{}
需要默认构造函数。但它确实需要!@user4581301是的,它可以编译。我现在正在写一个原因的答案。您好@user4581301,我认为它正在使用直接列表初始化,所以不需要默认构造函数,但我不完全确定(因此问题的最后一行!)没有任何东西。甚至没有考虑。鬼鬼祟祟。也有关联。嗨!NaNaLover,非常感谢!我错过了一些关于非默认/删除的构造函数和AGIGATE类。我还有一个关于你的答案的问题,尽管1 + 4和2 + 5的情况下,这两个调用完全相同的构造函数吗?我试着去读。C++引用,我开始说服自己,1 + 4执行AGIGATE初始化A和A1(因为Debug构造函数是由行1删除),但2+4调用A的默认构造函数,聚合初始化调用A1?请注意,OP调用List init的实际上是列表初始化。确切地说,它也是聚合初始化。聚合初始化是列表初始化的一种形式。@Andy在2+4中它仍然是聚合初始化的,只是它将使用t默认成员初始值设定项: