#cpp #language_lawyer #cpp14
void f(long long v) { cout << 1; } void f(int v) { cout << 2; } int main() { long l = 2L; f(l); return 0; } Есть такой код, при этом ошибка компиляции - неоднозначность, а почему?! Cтандарт C++ гарантирует, что sizeof(int) <= sizeof(long) <= sizeof(long long) И по правилам, расширение имеет больше приоритет чем стандартное преобразование. long в long long - расширение. long в int - стандартное преобразование. Скорей всего повлияло, в моей модели данных long = int = 4, а long long = 8. Какая тогда должна быть логика? Если long = int, почему бы не выбрать функцию с int аргументом? Если я попробую заменить long l = 2L на int l = 2, все удачно скомпилируется, из за точного соответствия. PS: Все попытки на c++14
Ответы
Ответ 1
Я не знаю, откуда вы взяли эту информацию о каком-то "расширении", которое якобы "имеет больше приоритет, чем стандартное преобразование". Язык С++ признает только два типа целочисленных преобразований при выполнении ранжирования неявных преобразований в процессе overload resolution. Это integral promotions и integral conversions (см. Table 12 в 13.3.3.1.2). Integral promotions - это преобразования, которым подвергаются "малые" целочисленные типы - [signed/unsigned] char и [signed/unsigned] short. Типы int, long и long long не могут подвергаться integral promotions, и к нашему случаю integral promotions никак не относятся. Все остальные преобразования между целочисленными типами являются integral conversions и имеют один и тот же ранг, независимо от того, являются ли они "расширяющими", "сужающими" или еще какими. В вашем случае преобразования long -> int и long -> long long являются integral conversions. Фактический размер типов на вашей платформе никакого значения не имеет. Ранжирование неявных преобразований полностью абстрагировано от этих размеров. Тот факт, что на вашей платформе int и long имеют одно и тоже физическое представление ничего не меняет. С точки зрения языка int и long - разные типы и между ними надо выполнять преобразования, пусть даже и чисто концептуальные. (Да, в С++ есть понятие сужающего (narrowing) преобразования, и преобразование из long в int в общем случае является сужающим, но при выполнении ранжирования неявных целочисленных преобразований этот момент не учитывается вообще.) В вашем случае обе функции-кандидата требуют integral conversion, т.е. преобразований одного и того же ранга. Значит вызов неоднозначен.Ответ 2
Обе функции одинаково хороши поэтому фиксируется неоднозначность (преобразований не нужно), тогда как для int нужно преобразование.Ответ 3
Дело в том, что в С++ все типы с разным названием различаются с точки зрения компилятора. И необходимы преобразования, даже несмотря на то, что их размеры совпадают. Ну, а раз необходимы преобразования, причём цепочки long → int и long → long long одинаково хороши, поэтому происходит ошибка выбора перегрузки. Однако синомимы, объявленные с помощью typedef, не различаются.
Комментариев нет:
Отправить комментарий