Почему неоднозначно вызывать перегруженные ambig (long) и ambig (unsigned long) с целочисленным литералом? - PullRequest
31 голосов
/ 07 января 2012

При компиляции

void ambig(  signed long) { }
void ambig(unsigned long) { }

int main(void) { ambig(-1); return 0; }

Я получаю

error C2668: 'ambig' : ambiguous call to overloaded function
    could be 'void ambig(unsigned long)'
    or 'void ambig(long)'
while trying to match the argument list '(int)'

Я знаю, что могу «исправить» это, сказав -1L вместо -1, но почему / как именно это считается неоднозначным с самого начала?

Ответы [ 3 ]

33 голосов
/ 07 января 2012

Вы передаете int этой перегруженной функции.

Хотя человеческая интуиция говорит, что ambig(signed long) должно быть предпочтительным, потому что ваш ввод - отрицательное целое число (которое не может быть представлено как таковоеunsigned long), эти два преобразования на самом деле эквивалентны в «приоритете» в C ++.

То есть преобразование intunsigned long считается таким же действительным, как и intsigned long, и ни один из них не является предпочтительным для другого.

С другой стороны, если ваш параметр уже был long, а не int, то существует точное совпадение до signed long, без необходимости конвертации. Это позволяет избежать неоднозначности .

void ambig(  signed long) { }
void ambig(unsigned long) { }

int main(void) { ambig(static_cast<long>(-1)); return 0; }

"Просто одна из этих вещей".


[C++11: 4.13/1]: ("Целочисленный рейтинг конверсии")

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

  • [..]
  • Ранг целочисленного типа со знаком должен быть большечем ранг любого целочисленного типа со знаком меньшего размера.
  • ранг long long int должен быть больше ранг long int, который долженбыть больше, чем ранг int, который должен быть больше, чем ранг short int, который должен быть больше, чем ранг подписанного символа.
  • ранг любого неподписанногоЦелочисленный тип должен равняться рангу соответствующего целочисленного типа со знаком.
  • [..]

[ Примечание: Используется целочисленный ранг преобразованияв определении интегральных продвижений (4.5) и обычных арифметических преобразований (п. 5). - конец примечания ]

Разрешение перегрузки является сложным и определяется в [C++11: 13.3];Я не буду утомлять вас, цитируя большинство из них здесь.

Вот основной момент:

[C++11: 13.3.3.1/8]: Если не требуется преобразований для сопоставления аргумента с параметромтипом, последовательность неявного преобразования является стандартной последовательностью преобразования, состоящей из преобразования идентификаторов (13.3.3.1.1).

[C++11: 13.3.3.1/9]: Если не найдена последовательность преобразований для преобразования аргумента в тип параметра илив противном случае преобразование является некорректным, неявная последовательность преобразования не может быть сформирована.

[C++11: 13.3.3.1/10]: Если существует несколько различных последовательностей преобразования, каждая из которых преобразует аргумент в тип параметра, последовательность неявного преобразования, связанная с параметромопределяется как уникальная последовательность преобразования, обозначаемая неоднозначной последовательностью преобразования.В целях ранжирования последовательностей неявного преобразования, как описано в 13.3.3.2, неоднозначная последовательность преобразования обрабатывается как определенная пользователем последовательность, которая неотличима от любой другой определенной пользователем последовательности преобразования134.Если в качестве наилучшей жизнеспособной функции выбрана функция, использующая последовательность неоднозначных преобразований, вызов будет некорректным, поскольку преобразование одного из аргументов в вызове неоднозначно.

  • /10 - это случай, который вы испытываете;/8 - это случай, который вы используете с аргументом long.
8 голосов
/ 07 января 2012

Константа -1 имеет тип int. Итак, вы звоните ambig с int в качестве аргумента. ambig не имеет перегрузки, которая принимает int, поэтому нам придется посмотреть на неявные преобразования, которые мы могли бы сделать. int может быть неявно преобразовано в long или unsigned long (среди прочего), оба из которых будут действительными аргументами ambig. Таким образом, компилятор не знает, какое преобразование выбрать, и вам нужно привести его вручную (или использовать для начала длинную константу (-1l) вместо константы int).

Тот факт, что -1 является отрицательным числом, не учитывает его, поскольку компилятор не смотрит на значение аргументов, а только на его тип.

3 голосов
/ 07 января 2012

Потому что -1 имеет тип intint может быть неявно преобразовано в signed long или unsigned long.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...