【发布时间】:2019-07-23 17:58:54
【问题描述】:
在 N4659 16.3.3.1 隐式转换序列说
10 如果存在多个不同的转换序列,每个转换序列都将参数转换为参数类型,则与参数关联的隐式转换序列被定义为指定为不明确的唯一转换序列转换顺序。出于对 16.3.3.2 中所述的隐式转换序列进行排序的目的,不明确的转换序列被视为用户定义的转换序列,与任何其他用户定义的转换序列没有区别[注意:此规则防止函数变为非-viable,因为它的参数之一的转换序列不明确。] 如果使用不明确的转换序列的函数被选为最佳可行函数,则调用将是错误的,因为调用中的参数之一的转换是模棱两可的。
(当前草稿对应部分为12.3.3.1)
这个规则的预期目的和它引入的模糊转换序列的概念是什么?
文本中提供的注释指出,此规则的目的是“防止函数因其中一个参数的转换顺序不明确而变得不可行”。嗯...这实际上指的是什么? 可行函数 的概念在文档的preceding 部分中定义。它根本不依赖于转换的歧义(每个参数的转换必须存在,但它们不必是明确的)。而且似乎没有规定 viable 函数以后会以某种方式“变得不可行”(既不是因为一些歧义,也不是因为其他任何事情)。列举了可行的函数,它们根据certain rules相互竞争成为“最好的”,如果有一个“赢家”,则解析成功。在这个过程中,一个可行的功能可能(或需要)变成一个不可行的功能。
上述段落中提供的示例不是很有启发性(即不清楚上述规则在该示例中扮演什么角色)。
这个问题最初与这个简单的例子有关
struct S
{
operator int() const { return 0; };
operator long() const { return 0; };
};
void foo(int) {}
int main()
{
S s;
foo(s);
}
让我们在这里机械地应用上述规则。 foo 是一个可行的功能。从参数类型S 到参数类型int 有两个隐式转换序列:S -> int 和S -> long -> int。这意味着根据上述规则,我们必须将它们“打包”成一个模糊的转换序列。然后我们得出结论foo 是最佳可行函数。然后我们发现它使用了我们的模糊转换序列。因此,根据上述规则,代码格式错误。
这似乎没有意义。这里的自然期望是应该选择S -> int 转换,因为它的排名高于S -> long -> int 转换。我知道的所有编译器都遵循“自然”的重载决议。
那么,我误会了什么?
【问题讨论】:
-
荒谬的转换序列旨在排除恒等转换序列。 Like this
-
@Johannes Schaub - litb:引用的文字并没有说只有同等排名的转换序列必须“打包”到一个不明确的转换序列中。它只是说“如果存在多个不同的转换序列......”如果您有多个不同的序列,则必须将它们打包成一个模糊的转换序列,无论其中一个是否更好是否比其他人。
-
@Johannes Schaub - litb:我不明白你在说什么。再次:我在这里看到两个不同的转换序列
S -> int和S -> long -> int。怎么只有一个?请注意,这种将多个转换序列“打包”到一个模糊转换序列的过程很早就完成了:在我们开始对隐式转换序列进行排名并选择最佳可行函数之前。 -
@AnT 对应的规则建立
-> int和-> long部分表示“重载分辨率用于选择要调用的转换函数”。 (请注意,这是一个 嵌套 重载决议,具有自己的隐式转换序列,不要与foo的重载决议混淆)。在这种情况下,过载解决方案使用仲裁 (eel.is/c++draft/over.match#best-2.2) 选择了operator int,因为int -> int优于long -> int。所以这里没有用户定义的使用operator long的转换序列。
标签: c++ language-lawyer implicit-conversion overload-resolution conversion-operator