在重载解析中,选择使用不明确转换序列的函数是否必然会导致调用格式不正确

In overload resolution, does selection of a function that uses the ambiguous conversion sequence necessarily result in the call being ill-formed?

本文关键字:是否 函数 必然会 不正确 格式 调用 转换 重载 选择 不明确      更新时间:2023-10-16
这个问题

是在我研究这个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;
}

aint的转换可以通过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(。用户定义的转换因此 调用 Selected 以将初始值设定项表达式转换为 正在初始化的对象。如果转换无法完成或 模棱两可,初始化格式不正确。
  • [...]

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

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

  • 对于某些参数jICSj(F1)是比ICSj(F2)更好的转换序列,或者,如果不是这样,
  • 上下文是通过用户定义的转换(请参阅 8.5、13.3.1.5 和 13.3.1.6(和从返回类型F1到目标类型的标准转换序列(即 正在初始化的实体(是比 从返回类型F2到 目标类型。

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

由于从 intint(完全匹配排名(的标准转换序列优于从 charint(升级排名(的标准转换序列,因此第一个优于第二个,并且应该没有歧义 - operator int()定义的转换将用于初始化,然后与 §13.3.3.1 [over.best.ics]/p10 中的句子相矛盾,该句子表示函数调用由于歧义而格式不正确。

上面的分析有什么问题,还是那句话是标准中的错误?

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

§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无法区分。如果使用不明确的函数 选择转换序列作为最佳可行函数,调用将格式不正确,因为转换 调用中的一个参数是模棱两可的。

相关文章: