2011-08-18 19 views
7

La pregunta es en referencia a this, que fue publicado poco tiempo antes.
Mientras que el OP estaba feliz de aceptar la respuesta que resolvió su problema, estaba un poco intrigado con un detalle de por qué el compilador dio un error aparentemente incorrecto.¿Por qué el compilador no detecta la firma de la función correcta por error?

A continuación se muestra un pequeño ejemplo de código que he creado para demostrar la misma:

class YourClass 
    { 
    }; 

    class YourClass2 
    { 
    }; 
    class MyClass 
    { 
     public: 
      void doSomething(YourClass2 obj) 
      { 
       //Nothing more Interesting to do 
      } 

    }; 

    int main() 
    { 
     YourClass *ptr = new YourClass(); 
     MyClass obj; 
     obj.doSomething(ptr); 

     return 0; 
    } 

Compilación this con GCC (4.3.4) da un resultado de error aparentemente extraña:

prog.cpp: In function ‘int main()’: 
prog.cpp:23: error: no matching function for call to ‘MyClass::doSomething(YourClass*&)’ 
prog.cpp:13: note: candidates are: void MyClass::doSomething(YourClass2) 

Entonces la pregunta es:
¿Por qué tratar el compilador de la llamada,

obj.doSomething(ptr); 

como llamada a una función con el prototipo,

MyClass::doSomething(YourClass*&) 

y no

MyClass::doSomething(YourClass*) 

que parece ser el caso obvio.

Respuesta

4

Como han dicho otros, el compilador intenta ser útil y probablemente le confunda. Vamos a empezar con el error más simple:

error: no matching function for call to obj.doSomething(ptr)

Mientras el mensaje de error es correcto, la información que proporciona es muy limitado. En este ejemplo, el código es simple de seguir, pero considere una pieza de código más compleja. Leíste el mensaje de error y puedes pensar ... ¿Qué es obj ?, ¿qué es ptr? Por lo tanto, trata de ayudar a usted y le dice lo que obj es:

error: no matching function for call to ‘MyClass::doSomething(ptr)’

Bueno, eso es mejor, le está diciendo al menos en clase en la que hay que buscar la sobrecarga, pero tenga en cuenta que la clase era std::ostream y la función operator<< ... hay demasiadas sobrecargas, y aún así, ¿cuál es el tipo de ptr? Por lo tanto, se mueve hacia adelante y trata de describir el argumento: El argumento es un valor- de tipo YourClass* ... y he visto ese tipo de mensaje de error producido en el pasado:

error: no matching function for call to ‘MyClass::doSomething’ that takes an YourClass* lvalue as argument.

Ok, por lo que el error el informe está completo Ahora piense que la función puede tener más argumentos, y el mensaje de error puede convertirse en una bestia compleja (imagine una lista de 5 "rvalue de tipo XXX y un lvalue de tipo YYY y ..."). Lo siguiente es hacer que la sintaxis del mensaje de error sea igual de precisa (lvalue -ness del argumento es importante, o rvalue -ness sería importante, por lo que esa información debe estar presente). Por lo que vuelve a escribir el mensaje de error:

error: no matching function for call to ‘MyClass::doSomething(YourClass*&)’

El problema es que usted está tratando de interpretarlo como una firma de función, sino que es más bien la descripción de la llamada a la función.

Los mensajes de error no están definidos en el estándar, y difieren de un compilador a otro, incluso de una versión a otra dentro del mismo compilador. Al final del día, debe aprender a leer los mensajes de error y lo que significan.

+0

+1. Me gustó el análisis paso a paso del mensaje del compilador. :-). Y el punto más importante es 'El problema es que estás tratando de interpretar eso como una firma de función, pero es más bien la descripción de la llamada de función. – Nawaz

0

El compilador no se requiere para generar el mensaje que debe tener sentido para ti. Todo lo que necesita para decirle que hay un error en su código. Ahora qué mensajes imprime, depende del compilador. El estándar no dice qué mensaje debe imprimir, y qué no. Cuando el compilador imprime un mensaje de error, ese mensaje de error puede ser bueno/útil, o malo/inútil, pero no "incorrecto", en mi opinión.

+2

Lo sé, la cuestión es que el compilador no necesita ningún esfuerzo especial para detectar la firma de la función y, sin embargo, da un mensaje de diagnóstico que no coincide. Pregunta es ¿Por qué? –

6

En primer lugar, cabe destacar que la expresión ptr (no la variable de ptr) tiene el tipo YourClass *&. Esto es importante; que es la única manera de tipos de referencia pueden trabajar (de lo contrario se estaría haciendo una referencia a una copia cuando haces YourClass *&x = ptr, y es también la razón por YourClass *&x = (ptr + 1) falla). Como tal, el compilador comienza su búsqueda de una función con MyClass::doSomething(YourClass *&).

Por supuesto, esta llamada puede coincidir con un prototipo MyClass::doSomething(YourClass *). También puede coincidir con MyClass::doSomething(const YourClass *) o muchos otros. Hay potencialmente docenas (o, con múltiples parámetros, fácilmente cientos o miles) de prototipos que podrían coincidir con esta llamada; sin embargo, no se pudo encontrar ninguno.

lo que el compilador se da por vencido, y da un error. En el error, en lugar de enumerar todas las coincidencias teóricamente posibles, cita el prototipo que más se aproxima a lo que estaba buscando originalmente; es decir, MyClass::doSomething(YourClass *&).

+0

¿Cómo es la primera firma la más general? Creo que ese es el que tiene una conversión implícita, en lugar de la segunda. –

+0

@bdonlan: Bueno, surge otra pregunta: ¿por qué el compilador busca de esa manera? ¿Stardard lo requiere de esa manera? – Nawaz

+1

Si bien puede hacer una conversión de Foo a Foo &, eso implica que se forzará una copia incluso si fuera posible una referencia. – bdonlan

1

El compilador está tratando de ser útil.

MyClass::doSomething(YourClass*&) 

Esto no nombra ninguna función: no hay función en su código que coincida con esto.

YourClass*& es el tipo de argumento que está intentando pasar a una función llamada MyClass::doSomething: el argumento (ptr) es un valor-I, representado en el error por el &.

El compilador necesita alguna forma de distinguir los argumentos lvalue de los argumentos rvalue para proporcionarle la mayor cantidad posible de información de diagnóstico útil; esta es una manera sucinta de hacer esto.

Cuestiones relacionadas