overload ambiguous (int -> int64_t vs int -> double)

From [over.ics.user] table 12 we have

enter image description here

As you can see integer and floating point promotions have the same rank and integer and floating point conversions have the same rank.

Now we need to determine if 5 -> int64_t is a integer promotion or conversion. If we check [conv.prom]/1 we find

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

The promotion stops at int so we have to look at [conv.integral]/1 which is integer conversion and we have

A prvalue of an integer type can be converted to a prvalue of another integer type. A prvalue of an unscoped enumeration type can be converted to a prvalue of an integer type.

Which is what is going on. So 5 -> int64_t is integer conversion and 5 -> double is floating point conversion which are both ranked the same so the overload resolution is ambiguous.


I'm afraid this really comes down to "because it is".

Integer promotion ends at int; there is no promotion to types larger than int. So, you're left with two bog-standard implicit conversions, and it just so happens that they are equally good matches.

[C++14: 4.5/1]: A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

[C++14: 4.5/7]: These conversions are called integral promotions.

[C++14: 5/10]: [..] This pattern is called the usual arithmetic conversions, which are defined as follows:

  • If either operand is of scoped enumeration type (7.2), no conversions are performed; if the other operand does not have the same type, the expression is ill-formed.
  • If either operand is of type long double, the other shall be converted to long double.
  • Otherwise, if either operand is double, the other shall be converted to double.
  • Otherwise, if either operand is float, the other shall be converted to float.
  • Otherwise, the integral promotions (4.5) shall be performed on both operands [..]

Perhaps, when the use of long int and long long int became popular (particular through type aliases in cstdint and friends), the standard could have been modified to introduce integral promotions to these types. Then your conversion would not be ambiguous. However, lots of existing code could also have been broken.

Since performing a cast instead is a cheap fix, I doubt this is deemed worthwhile to "fix" by the standard committee.

Perhaps tellingly, the relatively new fixed-width char types can be promoted in this fashion:

[C++14: 4.5/2]: A prvalue of type char16_t, char32_t, or wchar_t (3.9.1) can be converted to a prvalue of the first of the following types that can represent all the values of its underlying type: int, unsigned int, long int, unsigned long int, long long int, or unsigned long long int. If none of the types in that list can represent all the values of its underlying type, a prvalue of type char16_t, char32_t, or wchar_t can be converted to a prvalue of its underlying type.

Tags:

C++