为什么最负的 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 可以是一个u
、U
、l
、L
、ll
或 LL
。这里没有任何地方包含 -
作为十进制文字的一部分。
在§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 为何令人困惑,首先:考虑下面 2147483647
的 signed int
二进制表示。
接下来,给这个数字加一:给出 -2147483648
中的另一个 signed int
(OP 希望使用)
最后: 我们可以看到为什么当 -2147483648
编译为 long int
而不是 signed int
时 OP 会感到困惑,因为它显然适合 32 位.
但是,正如当前答案所提到的,一元运算符 (-
) 被应用 after resolving 2147483648
这是一个 long int
并且不适合 32 位。
我正在学习 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 可以是一个u
、U
、l
、L
、ll
或 LL
。这里没有任何地方包含 -
作为十进制文字的一部分。
在§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 为何令人困惑,首先:考虑下面 2147483647
的 signed int
二进制表示。
接下来,给这个数字加一:给出 -2147483648
中的另一个 signed int
(OP 希望使用)
最后: 我们可以看到为什么当 -2147483648
编译为 long int
而不是 signed int
时 OP 会感到困惑,因为它显然适合 32 位.
但是,正如当前答案所提到的,一元运算符 (-
) 被应用 after resolving 2147483648
这是一个 long int
并且不适合 32 位。