int numeral -> правила перетворення покажчика


19

Розглянемо наступний код.

void f(double p) {}
void f(double* p) {}

int main()
{ f(1-1); return 0; }

MSVC 2017 цього не компілює. Зрозуміло, існує неоднозначний перевантажений дзвінок, 1-1який такий же, як 0і тому може бути перетворений в double*. Інші хитрощі, як-от 0x0, 0Lабо static_cast<int>(0), теж не працюють. Навіть оголошення const int Zero = 0та виклик f(Zero)викликає ту саму помилку. Вона працює належним чином, лише якщо Zeroїї немає const.

Схоже, те саме стосується і GCC 5 і нижче, але не GCC 6. Мені цікаво, якщо це частина стандарту C ++, відомої помилки MSVC або налаштування в компіляторі. Допитливий Google не дав результатів.

Відповіді:


18

MSVC вважає 1-1нульовою константою покажчика. Це було правильним стандартом для C ++ 03, де всі інтегральні постійні вирази зі значенням 0були нульовими константами вказівника, але це було змінено так, що лише нульові цілі літерали є нульовими константами покажчика для C ++ 11 з CWG випуску 903 . Це суттєва зміна, як ви бачите у своєму прикладі, і як це також зафіксовано в стандарті, див. [Diff.cpp03.conv] стандарту C ++ 14 (проект N4140).

MSVC застосовує цю зміну лише у режимі відповідності. Тож ваш код буде компілюватися з /permissive-прапором, але я думаю, що зміна була реалізована лише в MSVC 2019, дивіться тут .

У випадку GCC GCC 5 за замовчуванням переходить у режим C ++ 98, тоді як GCC 6 та пізніші за замовчуванням переходять у режим C ++ 14, через що, здається, зміна поведінки залежить від версії GCC.

Якщо ви викликаєте fконстант нульового покажчика як аргумент, то виклик неоднозначний, оскільки константа нульового вказівника може бути перетворена на значення нульового вказівника будь-якого типу вказівника, і це перетворення має такий же ранг, як перетворення int(або будь-який інтегральний тип) до double.


-1

Компілятор працює правильно, відповідно до [over.match] та [conv] , точніше [conv.fpint] та [conv.ptr].

Стандартною послідовністю перетворення є [бла-бла] нуль або одна [...] плаваючо-інтегральна конверсія, перетворення вказівника, [...].

і

Первісне значення цілочисельного типу або незапечатаного типу перерахування може бути перетворене в перше значення типу з плаваючою комою. Результат є точним, якщо можливо [бла-бла]

і

Константа нульового покажчика - це ціле число, що знаходиться в прямому значенні, зі значенням нуль або [...]. Нульова константа вказівника може бути перетворена в тип вказівника; результат - нульове значення вказівника цього типу [бла-бла]

Тепер роздільна здатність перевантаження - це вибір найкращої відповідності між усіма функціями-кандидатами (які, як забавна функція, навіть не повинні бути доступними у місці виклику!). Найкраще співпадає з точними параметрами або, як альтернатива, найменшими перетвореннями. Нульова або одна стандартна конверсія може статися (... для кожного параметра), а нуль "кращий", ніж один.

(1-1)- ціле число, яке має значення 0.

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


1
Як цілочисельний літерал ? Це вираз, що містить дві цілі букви з значенням та оператором. 1-11-
волоський горіх

@walnut: Ви, мабуть, посилаєтесь на незручне формулювання "послідовність двійкових цифр, восьмеричних цифр, цифр або шістнадцяткових цифр" . Це дуже невдало формулювання чогось досить "очевидного", що говорить про те, що не так (тобто виключаючи мінусовий символ). З просто "цифрами" та педантично за визначенням "цифра" (одна з 0 ... 9) не можна мати жодних негативних літералів (таких як -1). Однак , оскільки тип типового підпису , однак, очевидно, необхідний, і це, мабуть, можливо (і загальновизнаний).
Деймон

1
Я маю на увазі граматику для цілочислового літералу, показану в стандартному посиланні, яке не відповідає 1-1. У C ++ немає негативних цілочисельних букв. -1- це вираз, що складається з 1цілого літералу (підписаного типу) та -оператора унарного мінусу. Дивіться також розділ "Примітки" на сайті cppreference.com .
волоський горіх

Безумовно, правда, що граматика її не має, але це неабияке значення. За необхідності та за визначенням, C ++ дуже має негативні літерали, оскільки, якщо ви явно не додаєте u, ваш літерал підписується за визначенням. Підписані типи мають негативні значення (приблизно 50% можливих значень - негативні). Прикро, що граматика (з тієї причини, яку я не знав би) вводить в оману таким чином, і хоча технічно (за граматикою) -1 є позитивним буквальним, заперечується, будь-якими іншими способами, звичайно, є негативним буквальний. Так само, як 3 + 4 - це буквальне слово.
Деймон

До речі - я спробував 0U. Те саме питання. Те, що я не пробував, - enumцінність. Можливо, названий змінив би щось. Я закінчив писати довгий вираз з decltypeі remove_reference.
користувач1334767
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.