Почему самое отрицательное значение int вызывает ошибку о неоднозначных перегрузках функций?

91

Я изучаю перегрузку функций в 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)неоднозначен

Но если взять одно и то же значение для an intи распечатать его, получится 2147483648. Меня буквально смущает такое поведение.

Почему такое поведение наблюдается только тогда, когда передается самое отрицательное число? (Поведение такое же, если shortиспользуется с -32768- фактически, в любом случае, когда отрицательное число и положительное число имеют одинаковое двоичное представление)

Используемый компилятор: g ++ (GCC) 4.8.5

бесконечная петля
источник
4
Минимальное значение Int - "выдача ошибки компилятора". Какая ошибка? Вы должны включить это в вопрос
Джастин
11
Понятно call of overloaded ‘display(long int)’ is ambiguous.
crashmstr 02
6
Не связано, но вам следует обновить компилятор. Уже есть GCC 7.1.
HolyBlackCat 02
4
Вот мое предположение: typeof(-2147483648) != int. Буквальное значение 2147483648слишком велико для a int, поэтому оно longотрицается
Джастин
3
Интересно, что g ++ (по крайней мере, 6.4 и 7.1) не жалуются, что int j{-2147483648};это сужающее преобразование. Это почти само по себе вопрос. Вероятно, это связано с разрешением (например) long longсужения значений constexpr 2147483647LLпри инициализации.
Тоби Спейт

Ответы:

145

Это очень тонкая ошибка. То, что вы видите, является следствием отсутствия отрицательных целочисленных литералов в C ++. Если мы посмотрим на [lex.icon], мы получим целочисленный литерал ,

целочисленный литерал
        десятичный литерал целочисленный суффикс opt
        [...]

может быть десятичным-буквальным ,

десятичный-литерал: десятичный-литерал с
        ненулевой цифрой
        ' opt digit

где цифра является [0-9]и отличной от нуля цифра является [1-9]и суффикс пар может быть один из u, U, l, L, ll, или LL. Здесь он не -является частью десятичного литерала.

В п. 2.13.2 мы также имеем:

Целочисленный литерал представляет собой последовательность цифр , что не имеет срока или показатель степени части, с дополнительными разделительными одинарными кавычками, которые игнорируются при определении его стоимости. Целочисленный литерал может иметь префикс, определяющий его основу, и суффикс, определяющий его тип. Лексически первая цифра последовательности цифр является наиболее значимой. Десятичное число буквальный (базовые десять) начинается с цифрой , отличной от 0 , и состоит из последовательности десятичных цифр.

(курсив мой)

Это означает, что -in -2147483648является унарным operator -. Это означает, -2147483648что фактически рассматривается как -1 * (2147483648). Так как 2147483648это слишком много для вас, intон повышается до a, long intи неоднозначность возникает из-за несоответствия.

Если вы хотите получить минимальное или максимальное значение для типа переносимым способом, вы можете использовать:

std::numeric_limits<type>::min();  // or max()
Натан Оливер
источник
2
-2147483647 - 1также будет работать без предупреждения как отрицательное буквальное выражение
Cœur
2
Или INT_MINдля наименее подробного варианта. Хотя менее общий.
MSalters 03
@NathanOliver, не могли бы вы объяснить мне этот случай display(2147483649);. Почему в этом случае нельзя вызвать функцию unsigned int? и почему он обрабатывает arg 2147483649как long int вместо unsigned int?
бесконечный цикл
2
@infiniteloop Десятичные целочисленные литералы идут от intдо long intдо long long int. Вы никогда не получите беззнаковый тип для десятичного литерала, если не используете суффикс u/ U.
NathanOliver 03
2
В этом примере да. Чтобы позвонить display(unsigned a), нужно либо display(1234u);или, display(static_cast<unsigned>(1234));либоunsigned foo = 1234; display(foo);
Натан Оливер
36

Выражение -2147483648фактически применяет -оператор к константе 2147483648. На вашей платформе intнельзя хранить 2147483648, он должен быть представлен более крупным шрифтом. Следовательно, выражение -2147483648не выводится как signed intболее крупный знаковый тип signed long int.

Поскольку вы не предоставляете перегрузку, longкомпилятор вынужден выбирать между двумя перегрузками, которые одинаково допустимы. Ваш компилятор должен выдать ошибку компилятора о неоднозначных перегрузках.

Франсуа Андриё
источник
4

Расширение ответов на другие вопросы


Чтобы прояснить, почему путают OP, сначала : рассмотрите signed intдвоичное представление 2147483647ниже.

Самый большой подписанный int




Затем добавьте один к этому числу : предоставив другой signed intиз -2147483648(который OP желает использовать) Наименьшее подписанное целое число



Наконец: мы можем понять, почему OP сбивается с толку при -2147483648компиляции в a long intвместо a signed int, поскольку он явно умещается в 32 бита.

Но, как упоминается в текущих ответах, унарный оператор ( -) применяется после разрешения, 2147483648которое является a long intи НЕ подходит для 32 бит.

бункерное погружение
источник