在重载决策中,选择使用模糊转换序列的函数是否必然导致调用不正确?

T.C*_*.C. 26 c++ language-lawyer overload-resolution implicit-conversion

当我研究这个SO问题的答案时,问题出现了.请考虑以下代码:

struct A{
    operator char() const{ return 'a'; }
    operator int() const{ return 10; }
};

struct B {
    void operator<< (int) { }
};

int main()
{
    A a;
    B b;
    b << a;
}
Run Code Online (Sandbox Code Playgroud)

ato 的转换int可以是via,a.operator char()然后是整数提升,也可以是a.operator int()身份转换(即根本没有转换).标准说(§13.3.3.1[over.best.ics]/p10,脚注省略,加粗我的;所有引用均来自N3936):

如果存在几个不同的转换序列,每个转换序列将参数转换为参数类型,则与参数相关联的隐式转换序列被定义为指定为模糊转换序列的唯一转换序列.为了按照13.3.3.2中的描述对隐式转换序列进行排序,模糊转换序列被视为用户定义的序列,与任何其他用户定义的转换序列无法区分.如果选择使用模糊转换序列的函数作为最佳可行函数,则调用将是错误的,因为调用中的一个参数的转换是不明确的.

在这里,B::operator<<(int)是唯一可行的候选者 - 因此是最好的可行候选者,即使参数的转换序列不明确的转换序列.然后,根据粗体句子,调用应该是格式错误的,因为"调用中的一个参数的转换是模糊的".

然而,我测试的编译器(g ++,clang和MSVC)实际上没有报告错误,这是有道理的,因为在通过重载决定选择调用函数之后,函数的"参数(8.3.5)应该被初始化(8.5,12.8) ,12.1)及其对应的参数"(§5.2.2[expr.call]/p4).这个初始化是复制初始化(§8.5[dcl.init]/p15),根据§8.5[dcl.init]/p17,导致新一轮的重载决策,以确定要使用的转换函数:

初始化器的语义如下.的目标类型 是对象或引用的类型被初始化和 源类型是初始化表达式的类型.如果初始化程序不是单个(可能带括号的)表达式,则不定义源类型.

  • [...]
  • 如果目标类型是(可能是cv限定的)类类型:[...]
  • 否则,如果源类型是(可能是cv限定的)类类型,则考虑转换函数.列举了适用的转换函数(13.3.1.5),并通过重载决策(13.3)选择最佳函数.调用如此选择的用户定义转换以将初始化表达式转换为正在初始化的对象.如果转换不能完成或不明确,则初始化是错误的.
  • [...]

在这轮重载决策中,§13.3.3[over.match.best]/p1中有一个决胜局:

F1如果对于所有参数i,可行函数被定义为比另一个可行函数F2更好的函数,ICSi(F1)并不是比转换序列更差的转换序列ICSi(F2),然后

  • 对于某些论证j,ICSj(F1)是一个更好的转换序列ICSj(F2),或者,如果不是,
  • 上下文是由用户定义的转换初始化(见8.5,13.3.1.5和13.3.1.6),从返回类型F1到目标类型的标准转换序列(即,被初始化的实体的类型)是转换序列比从返回类型F2到目标类型的标准转换序列更好.

(省略了列表的示例和其余部分)

由于从标准转换序列int,以int(完全匹配等级)比标准转换序列从更好charint(促销秩),所述第一节拍的第二,和应该没有歧义-由下式定义的转化operator int()将用于初始化,然后与§13.3.3.1[over.best.ics]/p10中的句子相矛盾,该句子说函数调用由于含糊不清将会形成错误.

在上面的分析中有什么不对,或者该句是标准中的错误?

Mar*_* A. 8

在为用户定义的转换序列决定最佳用户定义转换时,我们有一个重载候选集.

§13.3.3/ p1说:

定义ICSi(F)如下:

  • [...]

  • 让ICSi(F)表示隐式转换序列,它将列表中的第i个参数转换为可行函数F的第i个参数的类型.13.3.3.1定义了隐式转换序列,13.3.3.2定义了它的含义一个隐式转换序列是一个比另一个更好的转换序列或更差的转换序列.

给定这些定义,可行函数F1被定义为比另一个可行函数F2更好的函数,如果对于所有自变量i,ICSi(F1)不是比ICSi(F2)更差的转换序列,然后

- [...]

- 上下文是由用户定义的转换初始化(见8.5,13.3.1.5和13.3.1.6)以及从返回类型F1到目标类型的标准转换序列(即,正在初始化的实体的类型)是一个比从F2的返回类型到目标类型的标准转换序列更好的转换序列.

这适用于此

§13.3.3.1.2/ P2

2第二个标准转换序列将用户定义转换的结果转换为序列的目标类型.由于隐式转换序列是初始化,因此在为用户定义的转换序列选择最佳用户定义转换时,应用用户定义转换初始化的特殊规则(见13.3.3和13.3.3.1).

因此,operator int选择转换序列作为最佳匹配.

最后,我将§13.3.3.1/ p10改写为

如果存在几个不同的转换序列,每个转换序列将参数转换为参数类型并且不可能确定最佳候选者, 则与参数相关联的隐式转换序列被定义为指定为模糊转换序列的唯一转换序列.为了对如13.3.3.2中描述的隐式转换序列进行排序,将模糊转换序列视为用户定义的序列,其与任何其他用户定义的转换序列134无法区分.如果选择使用模糊转换序列的函数作为最佳可行函数,则调用将是错误的,因为调用中的一个参数的转换是不明确的.