为什么使用整数字面量调用重载的ambig(long)和ambig(unsigned long)会产生歧义?

31

编译时

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

int main(void) { ambig(-1); return 0; }

我理解为

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)'

我知道我可以通过使用-1L而不是-1来“修复”它,但为什么/如何这首先被认为是含糊的?

3个回答

35

你正在将一个整数 int 传递给这个重载函数。

虽然人的直觉认为应该优先选择 ambig(signed long),因为你的输入是负整数(不能被 unsigned long 表示),但实际上在 C++ 中这两种转换在 "优先级" 上是等价的。

也就是说,将 int 转换为 unsigned long 和将 int 转换为 signed long 是同样有效的转换,它们之间没有先后顺序之分。

另一方面,如果你的参数已经是 long 而不是 int,那么就会有一个精确匹配signed long,无需进行转换。 这样可以避免歧义。 点击此处查看示例。

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

int main(void) { ambig(static_cast<long>(-1)); return 0; }

"只是其中一些事情"。


[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 参数的情况。

3
等等,但将 int 转换成 long 总是不会丢失信息的。将 int 转换成 unsigned long 有一半的情况会导致信息丢失。为什么它们在排名上相同?! - user541686
10
好的,我会尽力进行翻译。以下是需要翻译的内容:Just curious: any reason not to use just -1L instead of that cast?只是好奇:为什么不直接使用“-1L”而要使用类型转换? - Mat
@Mehrdad:是的,但是 sizeof(int)sizeof(long) - Lightness Races in Orbit
@LightnessRacesinOrbit:不确定我是否理解你的推理。如果int是负数,结果会丢失该信息(因为它总是正数)。能够将其强制转换回来以获得正确的值并不意味着结果本身具有正确的值,对吗? - user541686
@Mehrdad:不,但这意味着信息也没有丢失。它不一定是一种缩小转换。当然,它可以是,这就是为什么我认为这有点愚蠢。而且它也不直观。 - Lightness Races in Orbit
显示剩余5条评论

8
常量-1的类型是int。所以你使用一个int作为参数调用了ambigambig没有接受int的重载,因此我们需要查看可以进行的隐式转换。 int可以隐式转换为longunsigned long(以及其他一些东西),这两个都是ambig的有效参数。因此编译器不知道选择哪个转换,您需要手动进行强制转换(或者一开始使用长整型常数-1l而不是整型常数)。
事实上,-1是负数并不影响它的处理,因为编译器只关注参数的类型,而不考虑其值。

4

因为-1int类型。而int可以隐式转换为signed longunsigned long


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接