首先,很重要的事:你有两种不同类型的构造函数。第一个特别是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