Перегрузка неоднозначная (int → int64_t vs int → double)

Почему неявное преобразование int в int64_t vs int в double неоднозначное?

Я бы подумал, что интегральная перегрузка будет иметь приоритет над интегралом с плавающей точкой?

#include <stdint.h>

void foo(double) {}
void foo(int64_t) {}

int main()
{
    foo(5);
    return 0;
}
main.cpp: In function ‘int main()’:
main.cpp:8:10: error: call of overloaded ‘foo(int)’ is ambiguous
     foo(5);
          ^
main.cpp:3:6: note: candidate: void foo(double)
 void foo(double) {}
      ^
main.cpp:4:6: note: candidate: void foo(int64_t)
 void foo(int64_t) {}
      ^

Моя среда:

  • x86_64
  • g++ - 5.4 (с -std=c++14)

int64_t является long int на моей машине:

/usr/include/stdint.h:

 # if __WORDSIZE == 64
 typedef long int        int64_t;
 # else

Я подтвердил это с помощью static assert в своем тестовом приложении:

static_assert(__WORDSIZE == 64, "");
static_assert(std::is_same<int64_t, long int>::value, "");

Мои флаги сборки:

-std=c++14 -Werror -Wall -Wextra -m64 -msse2 -msse4.2 -mfpmath=sse 
-ftemplate-depth-128 -Wno-unused-parameter -pthread  -g -ggdb3 -O0 -fno-inline

Ответ 1

Из таблицы [over.ics.user] 12 имеем

введите описание изображения здесь

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

Теперь нам нужно определить, является ли 5 -> int64_t целым продвижением или конверсией. Если мы проверим 4.5, найдем

Значение целочисленного типа, отличного от bool, char16_t, char32_t или wchar_t, чей целочисленный ранг преобразования (4.13) меньше ранга int, может быть преобразован в prvalue типа int, если int может представлять все значения тип источника; в противном случае исходное значение prvalue может быть преобразовано в prvalue типа unsigned int.

Продвижение останавливается на int, поэтому мы должны смотреть на 4.7, который является целым преобразованием, и мы имеем

Значение целочисленного типа может быть преобразовано в prvalue другого целочисленного типа. Prvalue неперечисленного типа перечисления может быть преобразован в prvalue целочисленного типа.

Это то, что происходит. Таким образом, 5 -> int64_t представляет собой целочисленное преобразование, а 5 -> double - преобразование с плавающей запятой, которые оба ранжируются одинаково, поэтому разрешение перегрузки неоднозначно.

Ответ 2

Я боюсь, что это действительно сводится к "потому что это".

Целое продвижение заканчивается на int; нет рекламы для типов, превышающих int. Таким образом, вы остаетесь с двумя неявными преобразованиями в болоте, и так получилось, что они одинаково хороши.

[C++14: 4.5/1]: Значение целочисленного типа, отличного от bool, char16_t, char32_t или wchar_t, чей целочисленный ранг преобразования (4.13) меньше ранга int, может быть преобразован в prvalue типа int, если int может представлять все значения типа источника; в противном случае исходное значение prvalue может быть преобразовано в prvalue типа unsigned int.

[C++14: 4.5/7]: Эти преобразования называются интегральными акциями.

[C++14: 5/10]: [..] Этот шаблон называется обычными арифметическими преобразованиями, которые определяются следующим образом:

  • Если либо операнд имеет тип перечисления с областью (7.2), конверсии не выполняются; если другой операнд не имеет одного и того же типа, выражение плохо сформировано.
  • Если любой из операндов имеет тип long double, другой должен быть преобразован в long double.
  • В противном случае , если либо операнд double, другой должен быть преобразован в double.
  • В противном случае, если любой операнд float, другой должен быть преобразован в float.
  • В противном случае интегральные акции (4.5) должны выполняться на обоих операндах [..]

Возможно, когда использование long int и long long int стало популярным (в частности, через псевдонимы типов в cstdint и друзьях), стандарт мог быть изменен, чтобы внедрить интегральные акции для этих типов. Тогда ваше обращение не будет двусмысленным. Однако многие существующие коды также могли быть повреждены.

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

Возможно, возможно, что относительно новые типы фиксированной ширины char могут быть продвинуты таким образом:

[C++14: 4.5/2]: Значение типа char16_t, char32_t или wchar_t (3.9.1) может быть преобразовано в prvalue первого из следующих типов, который может представлять все значения его базового типа: int, unsigned int, long int, unsigned long int, long long int или unsigned long long int. Если ни один из типов в этом списке не может представлять все значения его базового типа, prvalue типа char16_t, char32_t или wchar_t может быть преобразован в prvalue его базового типа.

Ответ 3

Компилятор прав... По умолчанию ваш числовой литерал 5 имеет тип int...

Чтобы выполнить этот вызов функции, должно произойти перегрузочное разрешение, которое в основном проверяет жизнеспособность преобразования. Обратите внимание, что это будет случай конверсии, а не продвижения по службе.

Теперь, чтобы объяснить, почему? Я расскажу историю из cppreference: (я знаю, не замена стандартного)

В выборе наилучшей жизнеспособной функции для разрешения перегрузки:

F1 определяется как лучшая функция, чем F2, если неявная преобразования для всех аргументов F1 не хуже, чем неявные преобразования для всех аргументов F2 и

  • существует хотя бы один аргумент F1, неявное преобразование которого лучше соответствующего имплицированного преобразования для этого аргумента F2
  • или,...
  • или,...

Теперь посмотрим, какая неявная последовательность преобразования:

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

  • нулевая или одна стандартная последовательность преобразования;
  • .,.

Теперь давайте посмотрим, что стандартная последовательность преобразования :

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

  • ноль или одно преобразование lvalue;
  • ноль или одно числовое продвижение или числовое преобразование;
  • .,

У вас есть это, отсюда, обратитесь к таблице в ответ NathanOliver..