使用initializer_list进行不明确的重载决策

Kar*_*lte 10 c++ visual-studio c++11

我在Visual Studio上测试了以下代码,它编译并打印"A(double)".

#include <iostream>
#include <initializer_list>

struct A {
    A(std::initializer_list<int>) { puts("initializer_list<int>"); }        // (1)
    A(std::initializer_list<float>) { puts("initializer_list<float>"); }    // (2)
    A(double) { puts("A(double)"); }                                        // (3)
};

int main() {
    A var{ 1.1 };   
}
Run Code Online (Sandbox Code Playgroud)

但是,IntelliSense和http://ideone.com/ZS1Mcm都不同意,他们说构造函数"A :: A"的多个实例与参数列表匹配(意味着两个初始化列表构造函数).请注意,如果删除了(1)或(2),则代码不再编译,因为"从'double'转换为'float'需要缩小转换".

这是一个错误吗?行为感觉不一致,但我在VS13和VS15中看到了相同的行为,所以可能还有更多呢?

Col*_*mbo 3

该代码格式不正确。\xc2\xa78.5.4/(3.6) 适用:

\n\n
\n

否则,如果T是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决策选择最好的构造函数(13.3、13.3.1.7)。

\n
\n\n

现在,\xc2\xa713.3.3.1.5 开始

\n\n
\n

当参数是初始值设定项列表 (8.5.4) 时,它不是表达式,并且应用特殊规则将其转换为参数类型。[\xe2\x80\xa6]\n 如果参数类型为std::initializer_list<X>且初始化器列表的所有\n 元素都可以隐式转换为X,\n 隐式转换序列是转换\n 的元素所需的最差转换list 到X,或者如果初始值设定项列表没有\n 元素,则进行恒等转换。

\n
\n\n

Converting1.1的类型为double(!), toint是具有转换等级的浮点积分转换,而 from 1.1to的转换float是浮点转换 - 也具有转换等级。

\n\n

在此输入图像描述

\n\n

因此,这两种转换同样好,并且由于 \xc2\xa713.3.3.2/(3.1) 也无法区分它们,因此调用是不明确的。请注意,在重载决策完成之前,缩小范围不会发挥作用,因此不会影响候选集或选择过程。更准确地说,候选人必须满足 13.3.2/3 中规定的要求:

\n\n
\n

其次,为了F成为一个可行的函数,每个参数都应存在一个隐式转换序列(13.3.3.1),该序列将该参数转换为 的相应参数F

\n
\n\n

然而,如第二个引用所示,转换{1.1}为 的隐式转换序列是从到 的std::initializer_list<int>最差转换,这是一种浮点积分转换 - 并且是一个有效的(并且现有的!)转换。1.1int

\n\n


\n如果您传递{1.1f}或更改initializer_list<float>to <double>,则代码格式良好,因为转换1.1ffloat是身份转换。标准在(3.6)中给出了相应的例子:

\n\n

\n

[例子

\n\n
struct S {\n    S(std::initializer_list<double>); // #1\n    S(std::initializer_list<int>);    // #2\n\n};\nS s1 = { 1.0, 2.0, 3.0 }; // invoke #1\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x80\x94结束示例]

\n
\n\n

更有趣的是,

\n\n
struct S {\n    S(std::initializer_list<double>); // #1\n    S(std::initializer_list<int>);    // #2\n\n};\nS s1 = { 1.f }; // invoke #1 \n
Run Code Online (Sandbox Code Playgroud)\n\n

也是有效的1.f- 因为从到 的转换double是浮点促销,具有促销排名,这比转换排名更好。

\n