为什么用整数字面调用重载的ambig(long)和ambig(unsigned long)是不明确的?

Meh*_*dad 31 c++ ambiguity visual-c++

编译时

void ambig(  signed long) { }
void ambig(unsigned long) { }

int main(void) { ambig(-1); return 0; }
Run Code Online (Sandbox Code Playgroud)

我明白了

error C2668: 'ambig' : ambiguous call to overloaded function
    could be 'void ambig(unsigned long)'
    or 'void ambig(long)'
while trying to match the argument list '(int)'
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过说-1L而不是-1,但为什么/如何在一开始就被认为是模棱两可的来"解决"它?

Lig*_*ica 34

你正在传递一个int这个重载的函数.

虽然人类直觉说ambig(signed long)应该首选,因为你的输入是一个负整数(不能用a表示unsigned long),这两个转换在C++中实际上等同于"优先级".

也就是说,转换intunsigned long被认为是一样为有效intsigned long,也不是优选的到另一个.

在另一方面,如果你的参数已经一个long,而不是一个int,然后有一个精确匹配signed long,没有必要的转换.这避免了歧义.

void ambig(  signed long) { }
void ambig(unsigned long) { }

int main(void) { ambig(static_cast<long>(-1)); return 0; }
Run Code Online (Sandbox Code Playgroud)

"只是其中之一".


[C++11: 4.13/1]: ("整数转换排名")

每个整数类型都有一个整数转换等级,定义如下:

  • [..]
  • 有符号整数类型的等级应大于具有较小大小的任何有符号整数类型的等级.
  • 等级long long int应大于等级long int,等级int应大于等级short int,等级应大于等级的等级.
  • 任何无符号整数类型的等级应等于相应的有符号整数类型的等级.
  • [..]

[ 注意:整数转换排名用于整数促销(4.5)的定义和通常的算术转换(第5条).- 尾注 ]

过载分辨率很复杂,定义在[C++11: 13.3]; 我不会在这里引用大部分内容而烦恼你.

不过,这里有一个亮点:

[C++11: 13.3.3.1/8]: 如果不需要转换来将参数与参数类型匹配,则隐式转换序列是由标识转换(13.3.3.1.1)组成的标准转换序列.

[C++11: 13.3.3.1/9]: 如果找不到将参数转换为参数类型的转换序列,或者转换不正确,则无法形成隐式转换序列.

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

  • /10就是你遇到的情况; /8是你与long参数一起使用的情况.

  • 只是好奇:任何理由不使用'-1L`代替那个演员? (10认同)
  • 等等,但`int`→`long`总是无损转换.`int`→`unsigned long`有一半是有损耗的.他们是如何/为什么排名相同?! (2认同)

sep*_*p2k 8

常量-1具有类型int.所以你ambigint一个参数来打电话.ambig没有接受的重载int,所以我们必须查看我们可以做的隐式转换.一个int可以隐式转换到一个long或一个unsigned long(除其他外),这两者都将是有效的参数ambig.所以编译器不知道要选择哪个转换,你需要手动转换(或者使用long constant(-1l)而不是int常量开始).

-1作为负数的事实不会影响它,因为编译器不查看参数值,只查看其类型.