Страницы

Поиск по вопросам

четверг, 5 декабря 2019 г.

Неодназначность перегрузки функции разными целыми типами

#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, не различаются.

Комментариев нет:

Отправить комментарий