【发布时间】:2021-03-22 15:58:23
【问题描述】:
#include <iostream>
void g(int*); //#1
void g(int (&arr)[2]); //#2
void f(int*); //#3
void f(int const*); //#4
int main(){
int arr[2] ={0};
f(arr); // choose #3
g(arr); //ambiguous
}
考虑上面的代码,#3 被选择为f(ptr),但是,g(arr) 给出了ambiguous 诊断。
选择最佳函数的规则定义为:
标准转换序列S1是比标准转换序列S2更好的转换序列如果
- S1 是 S2 的适当子序列(比较 [over.ics.scs] 定义的规范形式的转换序列,不包括任何左值变换;身份转换序列被认为是任何非- 身份转换序列)或者,如果不是这样
所以看看over.ics.scs#3
这些用于对标准转换序列进行排名。转换序列的排名是通过考虑序列中每个转换的排名和任何参考结合的排名来确定的。
根据我对上述规则的理解,我可以理解为什么#3是f(ptr)的最佳重载,即:
给定 S1 为 (arr => int*):
Array-to-pointer conversion -> (identity conversion)
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
当给定 S2 为 (ptr => int const*)
Array-to-pointer conversion -> Qualification conversions -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int const* int const* => int const*
由于identity conversion 是Qualification conversions 的正确子序列,因此 S1 优于 S2。因此,f(ptr) 的重载决议选择了 #3。
当我使用类似的过程来确定最适合g(arr) 时,我遇到了一个问题。
同样,给定 S1 为 (arr => int*)
Array-to-pointer conversion -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
当给定 S2 as(arr => int (&arr)[2])
当引用类型的参数直接绑定到参数表达式时,隐式转换序列是恒等转换,除非参数表达式的类型是参数类型的派生类,在这种情况下,隐式转换序列是派生到基础的转换
identity conversion
^^^^^^^^^^^^^^^^^^^
bind to reference
这里,S2 的identity conversion 是S1 的Array-to-pointer conversion 的正确子序列,因此它应该比S1 更好,为什么编译器抱怨g(arr) 是一个模棱两可的调用?
我对如何对标准转换序列进行排名有任何误读吗?如何比较两个标准 ICS(包含转换的排名)?
【问题讨论】:
-
目标示例使用函数模板,但相同的 ics 排名规则适用于实例化的函数。
-
@cigien 该示例不解释这个问题。尽管它们都有精确的排名,但是身份转换比任何其他具有精确排名的转换都要好。否则,为什么
f(ptr)是明确的,qualification conversion没有确切的排名吗? -
澄清一下,你问为什么调用
g(arr);是模棱两可的,对吗?或者您是否正在寻找专门针对您对规则的理解的回复? -
@cigien 两者。在我看来,
f(arr);和g(arr);中的每次转换都只包含exact rank 的转换,但为什么g(arr);是模棱两可的。我需要这些问题的解释。 -
啊,好的。为什么
f(arr)不模棱两可可能有一个目标,但我还是会重新提出这个问题。
标签: c++ language-lawyer