首先,很重要的事:你有兩種不同類型的構造函數。第一個特別是C(std::initializer_list<int>)
,被稱爲構造函數的初始化列表。第二個只是一個普通的用戶定義的構造函數。
[dcl.init.list]/P2
構造函數是一個初始化列表構造如果第一個參數是std::initializer_list<E>
型或參照可能CV-合格某種類型E
std::initializer_list<E>
的,並且沒有其他參數,否則所有其他參數都有默認參數(8.3.6)。
在一個含有一個或多個初始化子句列表初始化,初始值設定列表構造器被任何其他構造之前考慮。也就是說,初始化列表構造函數最初是重載解析期間唯一的候選項。
[over.match.list]/P1
當非聚合類類型T
的對象是列表初始化使得8.5.4指定重載解析是根據本節中的規則進行,過載分辨率在兩個階段中選擇的構造:
所以對於c1
和c2
雙方的聲明候選集僅包含的C(std::initializer_list<int>)
構造。
構造之後被選擇的參數進行評估,以查看是否存在的隱式轉換序列將它們轉換爲參數類型。這需要我們爲初始化列表轉換規則:
[over.ics.list]/P4(重點煤礦):
否則,如果該參數的類型是std::initializer_list<X>
和的所有元素初始化列表可以隱式轉換到X
,隱式轉換序列是必要的列表的一個 元件轉換爲X
最壞轉換,或者如果初始化列表沒有任何元素,身份轉換。
這意味着如果初始化程序列表中的每個元素都可以轉換爲int
,則存在轉換。
讓我們專注於c1
現在:對於初始化列表{{1, 2}, {3}}
,初始化子句{3}
可以轉換爲int
([over.ics.list] /p9.1),但不{1, 2}
(即int i = {1,2}
病-formed)。這意味着違反了上述報價的條件。
- 如果沒有可行的初始化列表:由於沒有轉換,重載因爲沒有其他可行的構造,我們帶回的[over.match.list]/P1的第二階段失敗找到構造函數,再次執行重載解析,其中候選函數是類
T
的所有構造函數,參數列表包含初始化程序列表的元素 。
注意最後措辭的變化。第二階段的參數列表不再是一個初始化列表,而是聲明中使用的braced-init-list的參數。這意味着我們可以根據初始化程序列表單獨而不是同時評估隱式轉換。
在初始化列表{1, 2}
,無論初始值設定子句可以轉換爲int
,所以整個初始化子句可以轉換爲initializer_list<int>
,同樣爲{3}
。然後選擇第二個構造函數解析重載解析。
現在,讓我們專注於c2
,現在這應該很容易。初始化列表構造首先計算,並且,使用{ {1}, {2} }
有可靠地存在於從{1}
和{2}
轉換到int
,所以選擇所述第一構造函數。
因此,爲什麼如果我將'C(std :: initializer_list,std :: initializer_list )'和'c2'聲明更改爲'C c2 {{1.0},{2}};'我會得到編譯器錯誤?根據你的回答,必須爲此選擇第二個構造函數。或者我做了錯誤的結論? [現場演示](http://coliru.stacked-crooked.com/a/e299e66462e220cf) –
alexolut
@alexolut [over.isc.list]/p4:「[...]和初始化程序列表中的所有元素可以爲 被隱含地轉換爲'X',「一個'double'可以被隱式轉換爲'int',所以這個條款成立。進一步閱讀:「隱式轉換序列是將列表元素 轉換爲」X「所需的最差轉換。這個隱式轉換序列是*縮小轉換序列*。所以並不是沒有找到一個可行的初始化列表構造函數(進入階段2意味着我們還沒有找到一個),而是轉換本身導致程序不合格。 – 0x499602D2
即,找到可行的構造函數,但自變量本身不可行(不合格)。在這種情況下,我們沒有達到第二階段。 - 我的理解正確嗎? – alexolut