繁体   English   中英

C ++ 11删除/默认的构造函数

[英]C++11 deleted/defaulted constructors

我对在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);
};

所以当我取消注释某些行的组合(并使用带有clang的c ++ 17标准标志进行编译)时,我会感到困惑:

  • 1,编译。 列出AA1 init,以及A2的默认复制构造函数
  • 2,编译。 A和列表init A1 (?)的默认构造函数,以及A2的默认复制构造函数
  • 1 + 3或2 + 3,由于删除了A2复制构造函数,无法编译
  • 1 + 4,编译。 A和列表init A1(?)的默认构造函数,以及A2的默认复制构造函数
  • 2 + 4,编译。 A和列表init A1 (?)的默认构造函数,以及A2的默认复制构造函数
  • 1 + 5,无法编译。 A缺少(删除)默认构造函数,而A1没有匹配的构造函数?
  • 2 + 5,无法编译。 没有匹配的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的默认复制构造函数

同样, AA1聚合初始化

2 + 4,编译。 A和列表init A1?的默认构造函数,以及A2的默认复制构造函数

AA1将被初始化聚合,但在初始化A时,它将使用Var的默认成员初始化程序[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}; 由于构造函数的参数太多等原因,将无法编译。

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

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

有关聚合和聚合初始化的更多信息: https//en.cppreference.com/w/cpp/language/aggregate_initialization

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM