And*_*ndy 4 c++ defaulted-functions deleted-functions list-initialization
我对在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);
};
Run Code Online (Sandbox Code Playgroud)
所以当我取消注释某些行的组合(并使用带有clang的c ++ 17标准标志进行编译)时,我会感到困惑:
A和A1,以及默认的复制构造函数A2A和列出init A1(?),以及A2的默认复制构造函数A2A和列表init A1(?),以及默认的复制构造函数A2A和列出init A1(?),以及A2的默认复制构造函数A缺少(删除)默认构造函数,没有匹配的构造函数A1?A1?我想我理解大部分内容,但我很困惑为什么1 + 5和2 + 5编译失败.任何人都可以解释编译器用来选择它将要使用的构造函数的逻辑,以及它为什么无法编译?
如果我认为在其他情况下调用的构造函数是错误的,您是否还可以指出所调用的内容,为什么?
1,编译.列出A和A1的init,以及A2的默认复制构造函数
在这种情况下,您所谓的List init实际上是聚合初始化,因为它StructTest是一个聚合.这是允许的,因为显式默认或删除的构造函数的存在仍然使该类成为聚合.
2,编译.A和列表init A1?的默认构造函数,以及A2的默认复制构造函数
A1 聚合初始化就像1中发生的那样.其余的都是正确的
1 + 3或2 + 3,由于删除了A2的复制构造函数,无法编译
这是预期的行为,因为复制构造函数被标记为已删除.
1 + 4,编译.A和列表init A1?的默认构造函数,以及A2的默认复制构造函数
同样,对于集合初始化A和A1
2 + 4,编译.A和列表init A1?的默认构造函数,以及A2的默认复制构造函数
A和A1将被聚合初始化,但它会使用的默认成员初始化Var初始化时A每[dcl.init.aggr] /5.1
1 + 5,无法编译.说A缺少(删除)默认构造函数,而A1没有匹配的构造函数?
图5是用户提供的非默认或删除的构造函数.这意味着StructTest不再是聚合,您不能再聚合初始化它.
2 + 5,无法编译.没有匹配的A1构造函数?
与1 + 5相同的原因
(这是其他答案的附加信息)
对于C++ 11,C++ 14/17和C++ 20,此代码的行为是不同的!由于聚合的定义不断变化.
在C++ 11中,类不是聚合,因为它有一个大括号或者是相等的初始值(= -1),所以大小写1不能编译.
在C++ 14和17中,类是聚合,其他答案涵盖了这种情况.
在C++ 20中,类不会再次成为聚合,因为有一个新规则,任何用户声明的构造函数都不会使一个类成为聚合; 所以case 1将再次停止编译,并且在case 2中,StructTest<int> A1{1};由于构造函数的参数太多等原因,将无法编译.