2011-04-14 11 views
7

Recientemente, un alumno me preguntó sobre un problema de compilación. La respuesta fue bastante simple, pero ahora estoy luchando por el motivo. Un ejemplo sencillo:Búsqueda de tipo de letra del parámetro de retorno

#include <iostream> 
#include <vector> 

struct MyStruct 
{ 
    typedef std::vector<int> MyIntVector; 

    MyIntVector CopyVector(MyIntVector const& vector); 
}; 


MyStruct::MyIntVector MyStruct::CopyVector(MyIntVector const& vector) 
^^^^^^^^ 
{ 
    MyIntVector vec; 
    return vec; 
} 

int main(int /*argc*/, char** /*argv*/) 
{ 
    MyStruct st; 
} 

Para ser válido el código C++ parámetro de retorno tiene que ser completo. Tanto para la respuesta y para hacer feliz al compilador/alumno.

¿Pero por qué el valor de retorno debe calificarse con la clase y el parámetro para la función no?

Siempre lo hice y sé que tiene que ver con la búsqueda de ADL, pero ahora que me lo pidieron, busqué una mejor respuesta.
¿Alguien puede darme una referencia a la especificación o una pista donde puedo encontrar algo más de información?

Respuesta

7

La estructura de la gramática es tal que el tipo de retorno es independiente de lo que se declara y es posible declarar (pero no definir) varias cosas con el mismo tipo. Esto es válido ++ C:

int f(int), g(int); 

así que tener el alcance preciso de los objetos declarados que influyen en la búsqueda para el tipo sería problemático. En

id1 ns1::f(int), ns2::g(int); 

donde se buscaría id1?

Se podrían haber agregado reglas especiales para usar en la definición de funciones (solo puede haber una definición de función, para que no haya ambigüedad, pero puede haber varios objetos), pero no estoy seguro de la posibilidad ha sido examinado, y creo que la complicación adicional no se vería compensada por la ventaja.

+1

Y no puede haber varias funciones * * Al igual que las declaraciones que muestran en su ejemplo. Para las declaraciones de amigos, esto también es realmente válido, semánticamente, creo: 'struct C {friend void A :: f(), B :: f(); }; '. –

3

Para continuar con el análisis, el compilador necesita averiguar qué es un tipo y qué no.

Lo único que puede ocurrir en el ámbito del espacio de nombres es una declaración, y la mayoría de las declaraciones C++ comienzan con un nombre tipo, pero este no es el caso en C. Al declararlo, el identificador indefinido ser un int con static visibilidad.

Independientemente de la posibilidad de compilar un programa, también hace que el analizador sea mucho más simple si puede proceder de principio a fin sin poner en cola tokens para una identificación posterior dentro del contexto de la clase.

C++ 11 para resolver el problema con la sintaxis de tipo de retorno de arrastre:

auto MyStruct::CopyVector(MyIntVector const& vector) -> MyIntVector { 
+0

Pero tenga en cuenta que algunas declaraciones no comienzan con un nombre de tipo. En particular, 'C :: operator int() {}' (función de conversión), 'C :: C() {}' (constructor) y 'C :: ~ C() {}' (destructor) no comenzar con un nombre de tipo. Todos comienzan con funciones de nomenclatura de declarator. –

+0

@Johannes: Pensé en cubrir más terreno en ese argumento, ya que hay excepciones obvias como 'namespace' y especificadores de clase de almacenamiento. Eso definitivamente salió mal. De todos modos, es solo un argumento falso ... – Potatoswatter

Cuestiones relacionadas