2009-07-16 9 views
7

No puedo entender por qué este trozo de código no se compila:Espacio de nombres enfrentadas en C++

namespace A { 
     class F {};    // line 2 
     class H : public F {}; 
} 

namespace B { 
     void F(A::H x);   // line 7 
     void G(A::H x) { 
       F(x);   // line 9 
     } 
} 

estoy usando gcc 4.3.3, y el error es:

s3.cpp: In function ‘void B::G(A::H)’: 
s3.cpp:2: error: ‘class A::F’ is not a function, 
s3.cpp:7: error: conflict with ‘void B::F(A::H)’ 
s3.cpp:9: error: in call to ‘F’ 

creo que debido a que en la línea 9 no hay prefijo de espacio de nombre, F(x) debe significar definitivamente solo B::F(x). El compilador intenta convertir x en su propia superclase. En mi entender, no debería. ¿Porque hace eso?

Respuesta

11

Esto se debe a que el compilador buscará la función en el mismo espacio de nombres de donde provienen sus argumentos. El compilador encontró el identificador A::F pero no es una función. En resultado obtendrás el error.

Es comportamiento estándar por lo que puedo recordar.

3.4.2 Argumento dependiente de búsqueda de nombre Cuando un nombre no se utiliza como el postfix-expresión en una llamada de función (5.2.2), otros espacios de nombres no considerados durante las operaciones de búsqueda no calificado habitual (3.4. 1) puede buscarse y se pueden encontrar las declaraciones de la función amiga de ámbito de espacio de nombres (11.4) que de otro modo no serían visibles. Estas modificaciones en la búsqueda dependen de los tipos de argumentos (y para los argumentos de la plantilla de plantilla, el espacio de nombres del argumento de la plantilla).

Para cada tipo de argumento T en la llamada a la función, hay un conjunto de cero o más espacios de nombres asociados y un conjunto de cero o más clases asociadas a considerar. Los conjuntos de espacios de nombres y clases están determinados por completo por los tipos de argumentos de función (y el espacio de nombres de cualquier argumento de plantilla de plantilla). Los nombres y las declaraciones de uso de Typedef utilizados para especificar los tipos no contribuyen a este conjunto. Los conjuntos de espacios de nombres y las clases se determinan de la siguiente manera ...

Esta regla permite escribir el siguiente código:

std::vector<int> x; 
// adding some data to x 
//... 

// now sort it 
sort(x.begin(), x.end()); // no need to write std::sort 

Y, por último: Debido Core Issue 218 algunos compiladores compilar el código en cuestión sin ningún error.

+1

La llamada búsqueda de Koenig, de hecho, se describe en la sección 3.4.2 del estándar de C++. –

+0

Entonces, si VS compila esto, ¿es un error? – liori

+0

¿Podría encontrar una referencia a esa afirmación? Nunca he oído hablar de una regla como esa ... – xtofl

4

¿Ha intentado utilizar otros compiladores todavía? Hay un gcc bug report aquí que está suspendido (lo que sea que eso signifique).

EDITAR: Después de algunas investigaciones, encontré esto more official bug.

+0

Este es un ejemplo mínimo de mi propio código que se compila en el VS2005 de mi amigo. Aunque no he probado esta pieza exacta. Y ... DeusAduro parece no tener problemas para compilarlo en VS2005. – liori

+0

El informe de error se parece bastante a esto, aunque implica plantillas, que tienen un esquema de búsqueda (de dos fases) diferente. – xtofl

+0

Nota: otros informan que VS2005 compila este código como se esperaba. Probé Comeau's Test Drive -> éxito. Parece que solo gcc parece sufrir esto. – xtofl

1

Muy extraño, He copiado y pegado directamente a VS 2005 y me da un error, que yo esperaba:

de error 1 error LNK2001: símbolo externo sin resolver "vacío __cdecl B :: F (clase A :: H) "

Porque no hemos definido realmente F (x) en el espacio de nombres B ... no estoy seguro de por qué Gcc está dando este error.

0

Acabo de intentar compilarlo en Visual Studio 2005 y funcionó bien. Me pregunto si se trata de una implementación interrumpida de Argument Dependent Lookup, donde el espacio de nombres de los argumentos se introdujo accidentalmente.

Cuestiones relacionadas