Почему самая отрицательная величина int вызывает ошибку в неоднозначных перегрузках функций?
Я изучаю перегрузку функции на С++ и натолкнулся на это:
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
. Я буквально путаюсь с этим поведением.
Почему такое поведение наблюдается только тогда, когда передается самое отрицательное число? (Поведение такое же, если a short
используется с -32768
- фактически, в любом случае, когда отрицательное число и положительное число имеют одинаковое двоичное представление)
Используется компилятор: g++ (GCC) 4.8.5
Ответы
Ответ 1
Это очень тонкая ошибка. То, что вы видите, является следствием отсутствия отрицательных целых литералов в С++. Если мы посмотрим на [lex.icon], получим, что целочисленный литерал,
целочисленный литерал
decimal-literal integer-suffix opt
[...]
может быть десятичным-литералом,
десятичный литерал:
ненулевая цифра
decimal-literal opt digit
где цифра [0-9]
, а ненулевая цифра [1-9]
, а суффикс par может быть одним из u
, u
, l
, l
, ll
или ll
. Нигде здесь он не включает -
как часть десятичного литерала.
В п. 2.2.13 мы также имеем:
Integer литерал представляет собой последовательность цифр, которая не имеет части периода или экспоненты, с необязательным разделением одинарных кавычек, которые игнорируются при определении его значения. Integer литерал может иметь префикс, который указывает его базу и суффикс, который указывает его тип. Лексически первая цифра последовательности цифр является наиболее значимой. Литерал десятичного целого числа (базовая десятка) начинается с цифры, отличной от 0, и состоит из последовательности десятичных цифр.
(акцент мой)
Это означает, что -
in -2147483648
является унарным operator -
. Это означает, что -2147483648
фактически рассматривается как -1 * (2147483648)
. Поскольку 2147483648
слишком много для вашего int
, оно продвигается до long int
, и двусмысленность исходит из того, что не соответствует.
Если вы хотите получить минимальное или максимальное значение для типа переносимым способом, вы можете использовать:
std::numeric_limits<type>::min(); // or max()
Ответ 2
Выражение -2147483648
фактически применяет оператор -
к константе 2147483648
. На вашей платформе int
не может хранить 2147483648
, она должна быть представлена более крупным типом. Следовательно, выражение -2147483648
не выводится signed int
, а более крупный подписанный тип, вероятно, signed long int
.
Поскольку вы не предоставляете перегрузку для long
, компилятор вынужден выбирать между двумя перегрузками, которые одинаково (в) действительны. Ваш компилятор должен выпустить ошибку компилятора об неоднозначных перегрузках.
Ответ 3
Расширение ответов других
Чтобы понять, почему OP запутался, сначала: рассмотрим двоичное представление signed int
2147483647
ниже.
![Largest signed int]()
Затем добавьте одно к этому номеру: добавив еще signed int
из -2147483648
(который OP хочет использовать)
Наконец:, мы можем понять, почему OP путают, когда -2147483648
компилируется в long int
вместо signed int
, так как он явно подходит для 32 бит.
Но, как указывают текущие ответы, унарный оператор (-
) применяется после решения 2147483648
, который является long int
и НЕ вписывается в 32 бита.