C++11 deleted/defaulted 构造函数
C++11 deleted/defaulted constructors
我有点困惑 how/why 在 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);
};
所以当我取消注释某些行组合时(并使用 c++17 标准标志和 clang 进行编译),我很困惑:
- 1、编译。列出
A
和 A1
的 init,以及 A2
的默认复制构造函数
- 2、编译。
A
和 list init A1
(?) 的默认构造函数,以及 A2 的默认复制构造函数
- 1 + 3 或 2 + 3,由于删除了
A2
的复制构造函数而无法编译
- 1 + 4,编译。
A
和 list init A1(?) 的默认构造函数,以及 A2
的默认复制构造函数
- 2 + 4,编译。
A
和 list init A1
(?) 的默认构造函数,以及 A2 的默认复制构造函数
- 1 + 5,编译失败。说
A
缺少(删除)默认构造函数,并且 A1
? 没有匹配的构造函数
- 2 + 5,编译失败。
A1
? 没有匹配的构造函数
我想我明白了其中的大部分内容,但我很困惑为什么 1 + 5 和 2 + 5 编译失败。谁能解释一下编译器对 select 它将要使用的构造函数所使用的逻辑,以及编译失败的原因?
如果我认为在其他情况下调用的构造函数是错误的,您能否也指出调用的是什么,为什么?
1, Compiles. List init's for A and A1, and the default copy constructor for A2
你所说的 List init 在这种情况下实际上是 aggregate initialization 因为 StructTest
是一个聚合。这是允许的,因为显式默认或删除的构造函数的存在仍然使 class 成为聚合。
2, Compiles. Default constructor for A and list init A1?, and the default copy constructor for A2
A1
像 1 中发生的那样聚合初始化。其余正确
1 + 3 or 2 + 3, Fails to compile because of the deleted copy constructor for A2
这是预期的行为,因为复制构造函数被标记为已删除。
1 + 4, Compiles. Default constructor for A and list init A1?, and the default copy constructor for A2
同样,A
和 A1
的聚合初始化
2 + 4, Compiles. Default constructor for A and list init A1?, and the default copy constructor for A2
A
和 A1
将被聚合初始化,但在每个 [dcl.init.aggr]/5.1[=28] 初始化 A
时它将使用 Var
的默认成员初始化器=]
1 + 5, Fails to compile. Says A is missing(deleted) a default constructor, and no matching constructor for A1?
5 是用户提供的非默认或删除的构造函数。这意味着 StructTest
不再是聚合,您不能再对其进行聚合初始化。
2 + 5, Fails to compile. No matching constructor for A1?
与 1 + 5 相同的原因
你所说的list init
其实就是聚合初始化。您的 class 在所有情况下都是一个聚合,但是当您取消注释第 5 行时 - 此时它不再是一个聚合。聚合 class 是一个 class,其中 all 构造函数默认(显式或隐式)或删除。您只有一个非默认、非删除的构造函数,因此除非您取消注释,否则您的 class 仍然是一个聚合。
考虑到这一点,您的大部分示例都围绕聚合初始化,除非您通过删除复制构造函数明确禁止复制或添加非默认复制构造函数并使 class 非-聚合。
关于聚合和聚合初始化的更多信息:https://en.cppreference.com/w/cpp/language/aggregate_initialization
(这是其他答案的附加信息)
此代码的行为对于 C++11、C++14/17 和 C++20 是不同的!由于 aggregate.
的定义不断变化
在 C++11 中,class 不是聚合,因为它有一个 大括号或相等初始化器 (= -1
),所以案例 1 无法编译。
在 C++14 和 17 中,class 是一个聚合,其他答案涵盖了这种情况。
在 C++20 中,class 将不再是聚合,因为有一条新规则,任何用户声明的构造函数都会取消 class 作为聚合的资格;所以情况 1 将再次停止编译,而在情况 2 中,StructTest<int> A1{1};
由于构造函数的参数过多等原因将无法编译
我有点困惑 how/why 在 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);
};
所以当我取消注释某些行组合时(并使用 c++17 标准标志和 clang 进行编译),我很困惑:
- 1、编译。列出
A
和A1
的 init,以及A2
的默认复制构造函数
- 2、编译。
A
和 list initA1
(?) 的默认构造函数,以及 A2 的默认复制构造函数
- 1 + 3 或 2 + 3,由于删除了
A2
的复制构造函数而无法编译
- 1 + 4,编译。
A
和 list init A1(?) 的默认构造函数,以及A2
的默认复制构造函数
- 2 + 4,编译。
A
和 list initA1
(?) 的默认构造函数,以及 A2 的默认复制构造函数
- 1 + 5,编译失败。说
A
缺少(删除)默认构造函数,并且A1
? 没有匹配的构造函数
- 2 + 5,编译失败。
A1
? 没有匹配的构造函数
我想我明白了其中的大部分内容,但我很困惑为什么 1 + 5 和 2 + 5 编译失败。谁能解释一下编译器对 select 它将要使用的构造函数所使用的逻辑,以及编译失败的原因?
如果我认为在其他情况下调用的构造函数是错误的,您能否也指出调用的是什么,为什么?
1, Compiles. List init's for A and A1, and the default copy constructor for A2
你所说的 List init 在这种情况下实际上是 aggregate initialization 因为 StructTest
是一个聚合。这是允许的,因为显式默认或删除的构造函数的存在仍然使 class 成为聚合。
2, Compiles. Default constructor for A and list init A1?, and the default copy constructor for A2
A1
像 1 中发生的那样聚合初始化。其余正确
1 + 3 or 2 + 3, Fails to compile because of the deleted copy constructor for A2
这是预期的行为,因为复制构造函数被标记为已删除。
1 + 4, Compiles. Default constructor for A and list init A1?, and the default copy constructor for A2
同样,A
和 A1
2 + 4, Compiles. Default constructor for A and list init A1?, and the default copy constructor for A2
A
和 A1
将被聚合初始化,但在每个 [dcl.init.aggr]/5.1[=28] 初始化 A
时它将使用 Var
的默认成员初始化器=]
1 + 5, Fails to compile. Says A is missing(deleted) a default constructor, and no matching constructor for A1?
5 是用户提供的非默认或删除的构造函数。这意味着 StructTest
不再是聚合,您不能再对其进行聚合初始化。
2 + 5, Fails to compile. No matching constructor for A1?
与 1 + 5 相同的原因
你所说的list init
其实就是聚合初始化。您的 class 在所有情况下都是一个聚合,但是当您取消注释第 5 行时 - 此时它不再是一个聚合。聚合 class 是一个 class,其中 all 构造函数默认(显式或隐式)或删除。您只有一个非默认、非删除的构造函数,因此除非您取消注释,否则您的 class 仍然是一个聚合。
考虑到这一点,您的大部分示例都围绕聚合初始化,除非您通过删除复制构造函数明确禁止复制或添加非默认复制构造函数并使 class 非-聚合。
关于聚合和聚合初始化的更多信息:https://en.cppreference.com/w/cpp/language/aggregate_initialization
(这是其他答案的附加信息)
此代码的行为对于 C++11、C++14/17 和 C++20 是不同的!由于 aggregate.
的定义不断变化在 C++11 中,class 不是聚合,因为它有一个 大括号或相等初始化器 (= -1
),所以案例 1 无法编译。
在 C++14 和 17 中,class 是一个聚合,其他答案涵盖了这种情况。
在 C++20 中,class 将不再是聚合,因为有一条新规则,任何用户声明的构造函数都会取消 class 作为聚合的资格;所以情况 1 将再次停止编译,而在情况 2 中,StructTest<int> A1{1};
由于构造函数的参数过多等原因将无法编译