如果第二個構造函數被註釋掉了,那麼S {{}}仍然是有效的表達式,但是在我的情況下調用了S {}的默認構造實例的move-constructor。
實際上,那不會發生什麼。在[dcl.init.list]的順序是:
對象或類型T的參考的列表的初始化被定義如下:
- 如果T是一個聚合類和初始化列表具有單個[...]類型cv U的元素,
- 否則,如果T是一個字符數組,
一旦您刪除S(void *)
構造函數,S
將成爲聚合 - 它沒有用戶提供的構造函數。由於原因,S() = default
不計爲用戶提供。來自{}
的總體初始化將最終對i
成員進行初始化。
爲什麼轉換構造了一個默認的第一個案件有優先權?
隨着void*
剩下的,讓我們繼續下去的項目列表:
- 否則,如果初始化列表中沒有的元素[...]
- 否則,如果T是一個專業化std :: initializer_list,[...]
- 否則,如果T是類類型,則考慮構造函數。列舉的適用構造函數爲 ,最好的是通過重載分辨率(13.3,13.3.1.7)選擇的。
[over.match.list]爲我們提供了兩相重載解析過程:
- 最初,候選功能初始化列表構造器(8.6。4)T和 參數列表由初始化程序列表作爲單個參數組成。
- 如果沒有找到可行的初始化列表構造函數,重載決議再次進行,其中 候選函數是T類的所有構造函數和參數列表由元素初始化列表的 的。
如果初始化列表沒有任何元素,T具有一個默認的構造,省略了第一階段。
S
沒有任何初始化列表構造函數,所以我們進入第二個項目符號和枚舉所有的{}
參數列表的構造函數。我們有多個可行的構造:
S(S const&);
S(S&&);
S(void *);
轉換序列在[over.ics.list]定義:
否則,如果參數是每13.3非聚合類X和重載解析.1.7選擇X的單個 最好構造C到執行從參數初始化列表X類型的對象的初始化:
- 如果C不是一個初始化列表構造器和初始化列表具有式CV的單個元件U,[...] - 否則,隱式轉換序列是用戶定義的轉換序列與第二個標準轉換序列的標識轉換。
和
否則,如果參數類型是不是一類:[...] - 如果初始化列表沒有任何元素,的隱式轉換的序列是恆等變換。
即,S(S&&)
和S(S const&)
構造都是用戶定義的轉換序列加上標識轉換。但S(void *)
只是一個身份轉換。
但是,[over.best.ics]有這樣額外的規則:
然而,如果目標是
- 構造或
的第一個參數 - 隱含的對象參數用戶定義的轉換函數
和構造或用戶定義的轉換函數是通過
候選 - 13.3.1.3,當[...]
- 13.3.1.4,13.3.1.5,或13.3.1.6(在所有情況下),或
- 的13.3.1.7第二階段時初始化列表具有恰好一個要素即本身初始化值列表,並且目標是X
類的構造函數的第一參數,以及轉換是X
或參考(可能是cv合格的)X
,
不考慮用戶定義的轉換序列。
這從考慮S(S const&)
和S(S&&)
排除作爲候選 - 它們是正是這種情況下 - 目標是所述構造的作爲[over.match.list]第二階段和所述目標的結果的第一參數作爲一個參考,從而可能CV-合格S
,並且這樣的轉換序列將是用戶定義的。
因此,剩下的唯一候選人是S(void *)
,所以它是平凡的最佳可行的候選人。
「*如果第二個構造已被註釋掉,則S {{}}仍然是有效的表達,但(我知道)移動構造函數從第{}被調用的情況下默認構造的實例。*」號它會聚合 - 用'brace'初始化'int'來初始化'S'。 – ildjarn
@ildjarn問題是仍然有效。 – Orient