簡體   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