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

Why does the most negative int value cause an error about ambiguous function overloads?

我正在学习 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,其中编译失败并显示错误

call of overloaded display(long int) is ambiguous

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

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

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

表达式-2147483648实际上是将-运算符应用于常量2147483648。在你的平台上,int不能存储2147483648,它必须用更大的类型来表示。因此,表达式 -2147483648 不会被推导为 signed int 而是一个更大的有符号类型 signed long int.

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

这是一个非常微妙的错误。您所看到的是 C++ 中没有负整数文字的结果。如果我们查看 [[=​​55=]] 我们会得到一个 整数文字 ,

integer-literal
        decimal-literal integer-suffixopt
        [...]

可以是 十进制文字,

decimal-literal:
        nonzero-digit
        decimal-literal ’ opt digit

其中 digit[0-9] 并且 nonzero-digit[1-9] 并且后缀 par 可以是一个uUlLllLL。这里没有任何地方包含 - 作为十进制文字的一部分。

在§2.13.2中,我们还有:

An integer literal is a sequence of digits that has no period or exponent part, with optional separating single quotes that are ignored when determining its value. An integer literal may have a prefix that specifies its base and a suffix that specifies its type. The lexically first digit of the sequence of digits is the most significant. A decimal integer literal (base ten) begins with a digit other than 0 and consists of a sequence of decimal digits.

(强调我的)

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

如果您想以可移植的方式获取类型的最小值或最大值,您可以使用:

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

扩展其他人的答案


为了阐明 OP 为何令人困惑,首先:考虑下面 2147483647signed int 二进制表示。




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



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

但是,正如当前答案所提到的,一元运算符 (-) 被应用 after resolving 2147483648 这是一个 long int 并且不适合 32 位。