Почему этот вызов функции неоднозначен?

Я читаю стандарт и пытаюсь понять, почему этот код не будет разрешен без приведения.

void foo(char c) { }

// Way bigger than char
void foo(unsigned long int) { }

int main()
{
   foo(123456789); // ambiguous
   foo((unsigned long int) 123456789); // works
}

Вот что там написано:

4.13. Рейтинг целочисленного преобразования [рейтинг конв.]

Каждый целочисленный тип имеет ранг целочисленного преобразования, определенный следующим образом:

- Ранг любого целочисленного типа без знака должен равняться рангу соответствующего целочисленного типа со знаком.

- Ранг char должен быть равен рангу signed char и unsigned char.

В частности, меня беспокоит то, что он не говорит ЛЮБОЙ целочисленный тип без знака, только беззнаковый символ. Я предполагаю, что char переводится в беззнаковый тип посредством преобразования. Это правда?


person user4073503    schedule 24.09.2014    source источник
comment
Возможно, 123456789U сделает это за вас.   -  person WhozCraig    schedule 24.09.2014
comment
В частности, меня беспокоит то, что он не говорит ЛЮБОЙ целочисленный тип без знака, только беззнаковый символ. Я предполагаю, что char переводится в беззнаковый тип посредством преобразования. Это правда? - Я бы рискнул, что вы неправильно понимаете значение 4.13 в Стандарте ... char не повышается до _2 _... проблема в том, как говорит AndreyT - что 123456789 - это int, и явно не лучше его усекать как char или передать его как unsigned long (long было бы так же плохо - unsigned здесь не имеет значения).   -  person Tony Delroy    schedule 24.09.2014
comment
Несмотря на название, ранг целочисленного преобразования на самом деле не используется для ранжирования целочисленных преобразований во время разрешения перегрузки.   -  person T.C.    schedule 24.09.2014
comment
Ни одно из преобразований не является безопасным - один подписан в беззнаковый, а другой - с большим шрифтом в меньший - так почему одна небезопасная операция должна преобладать над другой?   -  person David Schwartz    schedule 24.09.2014
comment
+1 За шорохи мои джимми   -  person skrrgwasme    schedule 25.09.2014
comment
он не говорит ЛЮБОЙ беззнаковый целочисленный тип, просто беззнаковый символ - о какой части вы имеете в виду? В том, что вы процитировали, я не вижу ничего, что могло бы дать какое-то исключительное отношение к unsigned char.   -  person AnT    schedule 25.09.2014


Ответы (1)


Это не имеет ничего общего с рангом типа, определенного в 4.13. 4.13 определены внутренние рейтинги, используемые для описания интегральных продвижений и обычных арифметических преобразований. Сами по себе они не влияют напрямую на разрешение перегрузки. Ранжирование, относящееся к разрешению перегрузки, определено в «13.3.3.1.1 Стандартные последовательности преобразования», а затем используется в «13.3.3.2 Ранжирование последовательностей неявного преобразования».

Итак, речь идет о ранге конверсии, как это определено в п. 13.3. 123456789 - это целочисленный литерал типа int на вашей платформе. Это означает, что для вызова версий вашей функции char и unsigned long требуется неявное преобразование из int в char или из int в unsigned long. В обоих случаях мы имеем преобразования типа «интегральное преобразование». Это означает, что обе функции в данном случае одинаково «плохи». Отсюда двусмысленность.

Если для одной из этих функций требуется простое интегральное продвижение (в отличие от интегрального преобразования), она получит разрешение, и вызов будет считаться однозначным. Но, увы, обе ваши функции требуют интегральных преобразований.

person AnT    schedule 24.09.2014
comment
Или другой взгляд на это: перегрузка вызова функции не делает различий между 123456789 и -123456789, оба они int. Преобразование -123456789 в unsigned long может привести к потере данных: как правило, преобразование из int в unsigned long может привести к потере данных. То же самое и с char. Теперь, используя конкретную константу 123456789, вы можете доказать, что она не будет потеряна, но правила перегрузки не учитывают это: тип 123456789 в вашей системе int, поэтому int используется для разрешения перегрузки. - person Yakk - Adam Nevraumont; 24.09.2014