С++ Перегрузка разных с помощью подписанных и unsigned int

При компиляции C++ с перегруженными определениями функций почему поведение продвижения по-разному различается между целыми типами с подписью и без знака? Это ожидаемое поведение?

В приведенном ниже примере вызов "fail" в main неоднозначен, но вызов "pass" - нет.

unsigned int fail(unsigned int a) {
  return a;
}

unsigned int fail(unsigned short a) {
  return a;
}

int pass(int a) {
  return a;
}

int pass(short a) {
  return a;
}


int main(){

  unsigned char a;
  char b;
  fail(a);
  pass(b);

  return 0;
}

Пример вывода (из clang, VS-компилятор дает что-то подобное):

fail.cpp:22:3: error: call to 'fail' is ambiguous
  fail(a);
  ^~~~
fail.cpp:1:14: note: candidate function
unsigned int fail(unsigned int a) {
             ^
fail.cpp:5:14: note: candidate function
unsigned int fail(unsigned short a) {
             ^
1 error generated.

Ответ 1

Согласно интегральному продвижению (акцент мой):

Следующие неявные преобразования классифицируются как интегральные рекламные акции:

  • signed char [...] может быть преобразован в int;
  • unsigned char [...] может быть преобразован в int если он может удерживать весь диапазон значений, а unsigned int иначе;
  • char может быть преобразован в int или unsigned int зависимости от базового типа: signed char или unsigned char (см. выше);

Обратите внимание, что все другие конверсии не являются рекламными акциями; например, разрешение перегрузки выбирает charint (продвижение) по charshort (преобразование).

В вашем случае, учитывая, что int способен удерживать весь диапазон значений как signed char и unsigned char, только int pass(int a) является продвижением, которое предпочтительнее, чем остальные три, которые являются конверсиями, и нет предпочтений среди конверсий.

Ответ 2

Эти implicit conversions действительно следуют различным правилам.

  • charint - продвижение

  • charshort - это преобразование

и продвижение выбирается по сравнению с конверсией, потому что оно запрещает любые потери точности. Вот почему pass пропуска.

В то время как

  • unsigned charunsigned int - продвижение только в том случае, если int не может представлять полный диапазон значений unsigned char can; если нет, продвижение - это unsigned charint.

Я подозреваю, что в вашем случае int действительно может представлять все значения в диапазоне unsigned char. Это означает, что fail имеет выбор между двумя двухэтапными переходами: unsigned charintunsigned int и unsigned charintunsigned short и не может решить между ними.

источник: http://en.cppreference.com/w/cpp/language/implicit_conversion