为什么最负的int值会导致有关模糊函数重载的错误?

问题描述 投票:88回答:3

我正在学习C ++中的函数重载,并遇到了这个问题:

void display(int a)
{
    cout << "int" << endl;
}

void display(unsigned a)
{
    cout << "unsigned" << endl;
}

int main()
{
    int i = -2147483648;
    cout << i << endl; //will display -2147483648
    display(-2147483648);
}

根据我的理解,int范围内给出的任何值(在我的情况下int是4字节)将调用display(int),超出此范围的任何值都将是不明确的(因为编译器无法决定调用哪个函数)。它对int值的完整范围有效,除了它的最小值,即-2147483648,其中编译失败并出现错误

调用过载的display(long int)是模棱两可的

但是将相同的值带到int并打印该值会得到2147483648。我对这种行为感到困惑。

为什么只有在传递最负数时才会观察到这种行为? (如果short-32768一起使用,行为是相同的 - 事实上,在任何情况下,负数和正数具有相同的二进制表示)

使用的编译器:g ++(GCC)4.8.5

c++ integer overloading negative-number ambiguous-call
3个回答
142
投票

这是一个非常微妙的错误。你所看到的是C ++中没有负整数文字的结果。如果我们看[lex.icon],我们得到一个整数字面,

整数字面 decimal-literal integer-suffixopt [...]

可以是小数字,

十进制文字: 非零数字 decimal-literal'opt数字

其中数字是[0-9],非零数字是[1-9],后缀par可以是uUlLllLL之一。这里没有任何地方包括-作为十进制文字的一部分。

在§2.13.2中,我们还有:

整数文字是一个没有句点或指数部分的数字序列,可选地分隔单引号,在确定其值时将被忽略。整数文字可以具有指定其基数的前缀和指定其类型的后缀。数字序列的词汇第一个数字是最重要的。十进制整数文字(十进制)以0以外的数字开头,由一系列十进制数字组成。

(强调我的)

这意味着-中的-2147483648是一元operator -。这意味着-2147483648实际上被视为-1 * (2147483648)。由于2147483648对于你的int来说太多了,所以它被提升为long int,并且模糊性来自不匹配。

如果要以便携方式获取类型的最小值或最大值,可以使用:

std::numeric_limits<type>::min();  // or max()

36
投票

表达式-2147483648实际上是将-算子应用于常数2147483648。在您的平台上,int无法存储2147483648,它必须用更大的类型表示。因此,表达式-2147483648不是推论为signed int,而是更大的签名类型signed long int

由于您没有为long提供重载,因此编译器必须在两个同样有效的重载之间进行选择。您的编译器应该发出有关模糊重载的编译器错误。


4
投票

扩展别人的答案


为了澄清OP混淆的原因,首先:考虑signed int2147483647二进制表示,如下所示。

Largest signed int


接下来,在这个数字上加一:给另一个signed int-2147483648(OP希望使用)Smallest signed int


最后:我们可以看到为什么当-2147483648编译成long int而不是signed int时,OP会混淆,因为它显然适合32位。

但是,正如目前的答案所提到的,一元算子(-)是在解析2147483648之后应用的,long int是qazxswpoi并且不适合32位。

© www.soinside.com 2019 - 2024. All rights reserved.