2012-01-07 12 views
31

Al compilar¿Por qué es ambiguo invocar ambig (long) y ambig (unsigned long) sobrecargados con un literal entero?

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

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

consigo

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 'arreglar' esto diciendo -1L en lugar de -1, pero ¿por qué/cómo es exactamente esta considerado ambigua en el primer lugar?

Respuesta

33

Estás pasando de int a esta función sobrecargada.

Aunque la intuición humana dice que ambig(signed long) debe ser preferida debido a que su entrada es un entero negativo (que no puede ser representado como tal por un unsigned long), los dos conversiones son, de hecho, equivalente en "precedencia" en C++.

Es decir, la conversión intunsigned long se considera que es tan válida como intsigned long, y tampoco se prefiere a la otra.

Por otro lado, si su parámetro eran ya un long en lugar de un int, entonces no es una coincidencia exacta -signed long, sin necesidad de conversión. This avoids the ambiguity.

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 conversión entera")

Cada tipo entero tiene un rango de conversión de número entero define como sigue:

  • [..]
  • El rango de un tipo entero con signo debe ser mayor que el rango de cualquier tipo entero con signo con un tamaño más pequeño.
  • El rango de long long int será mayor que el rango de long int, que deberá ser mayor que el rango de int, que deberá ser mayor que el rango de short int, que deberá ser mayor que el rango de firmado carbonizarse.
  • 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 de número entero se utiliza en la definición de las promociones integrales (4.5) y las conversiones aritméticas usuales (Cláusula 5). -end nota]

resolución de sobrecarga es complejo, y se define en [C++11: 13.3]; No te aburriré citando la mayoría aquí.

Aquí es un punto culminante, sin embargo:

[C++11: 13.3.3.1/8]: Si no se requieren conversiones para que coincida con un argumento para 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 si 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 de conversiones diferentes que convierten cada 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 secuencia de conversión ambigua. 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á experimentando; /8 es el caso que usa con un argumento long.
+2

Espera, pero 'int' →' long' es siempre una conversión sin pérdida. 'int' →' unsigned long' pierde la mitad de las veces. ¿Cómo/por qué son del mismo rango? – Mehrdad

+10

Simplemente curioso: ¿hay alguna razón para no usar solo '-1L' en lugar de ese molde? – Mat

+0

@Mat: No, ninguno. –

3

Porque -1 es del tipo int. Y int se puede convertir implícitamente a signed long o unsigned long.

8

La constante -1 tiene el tipo int. Entonces está llamando al ambig con un int como argumento. ambig no tiene una sobrecarga que acepta un int, por lo que tendremos que mirar las conversiones implícitas que podríamos hacer. Un int se puede convertir implícitamente a 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 comenzar).

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.