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

时间:2017-08-02 19:14:43

标签: c++ integer overloading negative-number ambiguous-call

我正在学习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

3 个答案:

答案 0 :(得分:141)

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

  

整数字面
   decimal-literal integer-suffix opt
  [...]

可以是 decimal-literal

  

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

其中数字[0-9]非零数字[1-9],后缀par可为u之一,{ {1}},UlLll。这里没有任何地方包含LL作为十进制文字的一部分。

在§2.13.2中,我们也有:

  

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

(强调我的)

这意味着-中的-是一元-2147483648。这意味着operator -实际上被视为-2147483648。由于-1 * (2147483648)对于2147483648来说太多了int,因此会将其提升为long int,并且歧义来自于不匹配。

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

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

答案 1 :(得分:35)

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

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

答案 2 :(得分:4)

扩展他人的答案

为了澄清OP混淆的原因,首先:考虑下面signed int的{​​{1}}二进制表示。

Largest signed int



接下来,在此号码中添加一个:给另一个2147483647 signed int(OP希望使用) Smallest signed int


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

但是,正如当前的答案所提到的,一元运算符(signed int)在 解析-之后应用 ,{{1}并且不适合32位。