c++ - que - ¿Por qué es ambiguo invocar ambig(long) y ambig(unsigned long) sobrecargados con un literal entero?
persona ambigua (3)
Al compilar
void ambig( signed long) { }
void ambig(unsigned long) { }
int main(void) { ambig(-1); return 0; }
yo obtengo
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)''
Sé que puedo ''arreglarlo'' diciendo -1L
vez de -1
, pero ¿por qué / cómo exactamente esto se considera ambiguo en primer lugar?
Está pasando un int
a esta función sobrecargada.
Aunque la intuición humana dice que ambig(signed long)
debe ser preferido porque su entrada es un número entero negativo (que no puede ser representado como tal por un unsigned long
), las dos conversiones son de hecho equivalentes en "precedencia" en C ++.
Es decir, la conversión int
→ unsigned long
se considera tan válida como int
→ signed long
, y ninguna es preferible a la otra.
Por otro lado, si su parámetro ya es un long
lugar de una int
, entonces hay una coincidencia exacta para la signed long
, sin necesidad de conversión. Esto evita la ambigüedad .
void ambig( signed long) { }
void ambig(unsigned long) { }
int main(void) { ambig(static_cast<long>(-1)); return 0; }
"Sólo una de esas cosas".
[C++11: 4.13/1]:
("Rango de conversión entero")Cada tipo entero tiene un rango de conversión entero definido de la siguiente manera:
- [..]
- El rango de un tipo de entero con signo debe ser mayor que el rango de cualquier tipo de entero con signo con un tamaño más pequeño.
- El rango de
long long int
será mayor que el rango delong int
, que será mayor que el rango deint
, que será mayor que el rango deshort int
, que será mayor que el rango de char firmado.- El rango de cualquier tipo de entero sin signo será igual al rango del tipo de entero con signo correspondiente.
- [..]
[ Nota: el rango de conversión entero se usa en la definición de las promociones integrales (4.5) y las conversiones aritméticas habituales (Cláusula 5). -finalizar nota ]
La resolución de sobrecarga es compleja y se define en [C++11: 13.3]
; No te aburriré citando la mayoría aquí.
Aquí hay algo destacado, sin embargo:
[C++11: 13.3.3.1/8]:
si no se requieren conversiones para hacer coincidir un argumento con un tipo de parámetro, la secuencia de conversión implícita es la secuencia de conversión estándar que consiste en la conversión de identidad (13.3.3.1.1).
[C++11: 13.3.3.1/9]:
si no se puede encontrar una secuencia de conversiones para convertir un argumento a un tipo de parámetro o la conversión no está bien formada, no se puede formar una secuencia de conversión implícita.
[C++11: 13.3.3.1/10]:
si existen varias secuencias diferentes de conversiones que cada una convierte el argumento al tipo de parámetro, la secuencia de conversión implícita asociada con el parámetro se define como la secuencia de conversión única designada como la conversión ambigua secuencia. Con el fin de clasificar las secuencias de conversión implícitas como se describe en 13.3.3.2, la secuencia de conversión ambigua se trata como una secuencia definida por el usuario que no se distingue de cualquier otra secuencia de conversión definida por el usuario134. Si se selecciona una función que utiliza la secuencia de conversión ambigua como la mejor función viable, la llamada estará mal formada porque la conversión de uno de los argumentos en la llamada es ambigua.
-
/10
es el caso que estás experimentando;/8
es el caso que usa con un argumentolong
.
La constante -1
tiene el tipo int
. Entonces estás llamando ambig
con un int
como argumento. ambig
no tiene una sobrecarga que acepte un int
, por lo que tendremos que mirar las conversiones implícitas que podríamos hacer. Un int
se puede convertir implícitamente en long
o unsigned long
(entre otras cosas), y ambos serían argumentos válidos para ambig
. Por lo tanto, el compilador no sabe qué conversión elegir y usted necesita lanzar manualmente (o usar una constante larga ( -1l
) en lugar de una constante int para empezar).
El hecho de que -1
sea un número negativo no lo tiene en cuenta porque el compilador no mira el valor de los argumentos, solo su tipo.
Porque -1
es de tipo int
. Y int
se puede convertir implícitamente a signed long
o unsigned long
.