2016-09-20 120 views
4

我試着去了解@bolov的第一接受答案的問題Deleted default constructor. Objects can still be created... sometimes [1]C++ 11的值初始化之前聚集初始化

好像我發現有一個錯誤,所以它弄亂整個解釋。

@bolov解釋了爲什麼這個代碼成功地C++ 11編譯:

方案A

struct foo { 
    foo() = delete; 
}; 

// All bellow OK (no errors, no warnings) 
foo f = foo{}; 
foo f = {}; 
foo f{}; // will use only this from now on. 

爲什麼這個代碼失敗在C++ 11編譯:

情形C

struct foo { 
    foo() = delete; 
    foo(int) {}; 
}; 

foo f{}; // error call to deleted constructor 

他說的重點是,第一個foo是一個聚合,第二個foo不是聚合。

然後他給出了cppreference摘錄:

類型T的對象的列表初始化的效果是: ...

  • 如果T是一個聚合類型,集合初始化被執行。這需要照顧的情況ABDE(和F在C++ 14)
  • 否則的T構造的方式分兩個階段考慮:

    • 所有構造函數採取的std :: initializer_list ...

    • 否則[...] T ...的所有構造參與重載解析[...]這需要護理的C(和F在C++ 11) ...

根據摘錄時你寫的foo f {};場景A你得到聚合初始化。這將是偉大的。但是,在C++ 11現實(#3337草案,最接近標準)你有不同的初始化順序

對象或類型T的參考的

列表初始化定義如下:

  • 如果初始化程序列表中沒有元素並且T是具有默認構造函數的類類型,則該對象將進行值初始化。否則,如果T是一個聚合,則執行聚合初始化(8.5.3)。1)

所以FOO˚F{}; in 方案A應導致值初始化,即將調用DELETED默認構造函數,並且代碼將無法編譯。

+2

我不知道你在問什麼。 – Barry

+0

試圖讓它更簡潔。 – JenyaKh

+0

@Quentin,好吧,我會盡量寫得更好。 – JenyaKh

回答

3

作爲Core Issue 1301結果,這是對C++ 11中的缺陷,用於表初始化的優先級變更情況:從一個物體或類型T的參考的

列表初始化定義如下:

  • 如果初始化程序列表中沒有元素並且T是具有默認構造函數的類類型,則對該對象進行值初始化。
  • 否則,如果T是一個聚集體,聚集體的初始化被執行(8.5.1)

到:一個對象或類型T的參考的

列表初始化被定義爲如下:

  • 如果T是一個聚集,進行聚合初始化(8.5.1)
  • OT herwise,如果初始化列表中沒有元素,而T是具有默認構造函數的類類型,則對該對象進行值初始化。

所以方案A中的foo{}仍然是聚合初始化。

+1

是的,我明白,但是這個改變是在#3367草案中,並且被C++ 14接受。但是在Wiki中,我讀到#3337草稿與C++ 11最接近。所以在C++ 11中,我們沒有改變,所以它在編譯時看起來像編譯器一樣,因爲C++ 11不應該考慮方案A作爲聚合初始化,是嗎? – JenyaKh

+3

@JenyaKh問題1301是一個缺陷C++ 11,因此一個符合C++ 11的編譯器應該實現這個改變 – Barry

+4

@JenyaKh缺陷報告被反向應用到相應的標準上,它們是補丁更新,如果你願意的話:) – Quentin