Чому найбільш негативне значення 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)неоднозначний

Але беручи одне і те ж значення в intі друкуючи значення, яке дає 2147483648. Мене буквально бентежить така поведінка.

Чому така поведінка спостерігається лише тоді, коли передано найбільш негативне число? (Поведінка однакова, якщо shortвикористовується а -32768- насправді, у будь-якому випадку, коли від'ємне число та додатне число мають однакові двійкові подання)

Використовуваний компілятор: g ++ (GCC) 4.8.5


4
Мінімальне значення Int - це "помилка компілятора". Яка помилка? Ви повинні включити це у запитання
Джастін

11
Я бачу call of overloaded ‘display(long int)’ is ambiguous.
crashmstr

6
Не пов'язані, але слід оновити компілятор. Вже існує GCC 7.1.
HolyBlackCat

4
Ось моє припущення: typeof(-2147483648) != int. Буквал є 2147483648, який є занадто великим для int, тому він є long, і його заперечують
Джастін,

3
Цікаво, що g ++ (принаймні 6.4 та 7.1) не скаржиться, що int j{-2147483648};це звуження перетворення. Майже варто питання саме по собі, це. Ймовірно, це пов’язано з дозволом (наприклад) long longзначень constexpr, таких як 2147483647LLзвуження при ініціалізації.
Toby Speight

Відповіді:


145

Це дуже тонка помилка. Те, що ви бачите, є наслідком відсутності цілісних від’ємних літералів у C ++. Якщо ми подивимося на [lex.icon], то отримаємо цілочисельний літерал ,

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

може бути десятковим літералом ,

десятковий-літерал:
        ненульовий-
        десятковий десятковий-літерал ' розрядна цифра

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

У пункті 2.13.2 ми також маємо:

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

(наголос мій)

Що означає, що -in -2147483648є одинарним operator -. Це означає -2147483648, що насправді трактується як -1 * (2147483648). Оскільки 2147483648для вас занадто багато, intвоно підвищується до значення long intі неоднозначність походить від того, що не відповідає.

Якщо ви хочете отримати мінімальне або максимальне значення для типу в переносній формі, ви можете використовувати:

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

2
-2147483647 - 1також буде працювати без попередження як негативний буквальний вираз
Cœur

2
Або INT_MINдля найменш багатослівного варіанту. Однак менш загальний.
MSalters

@NathanOliver, можеш люб'язно пояснити мені цю справу display(2147483649);. Чому в цьому випадку він не може викликати непідписаний int func? і чому це трактує arg 2147483649як довгий int замість unsigned int?
нескінченна петля

2
@infiniteloop Десяткові цілочисельні літерали переходять від intдо long intдо long long int. Ви ніколи не отримаєте непідписаний тип для десяткового літералу, якщо не використовуєте u/ Uсуфікс.
NathanOliver

2
У цьому прикладі так. Для дзвінка display(unsigned a)вам потрібно або display(1234u);або, display(static_cast<unsigned>(1234));абоunsigned foo = 1234; display(foo);
NathanOliver

36

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

Оскільки ви не забезпечуєте перевантаження для longкомпілятора, він змушений вибирати між двома перевантаженнями, які однаково справедливі. Ваш компілятор повинен видавати помилку компілятора про неоднозначні перевантаження.


4

Розширюючи відповіді інших


Щоб пояснити, чому OP плутається, спочатку : розглянемо signed intдвійкове представлення 2147483647, нижче.

Найбільша підписана міжнар




Потім додайте до цього номеру : надання іншого signed intз -2147483648(що ОП хоче використовувати) Найменший підписаний інт



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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.