2012-06-12 15 views
12

No es este código:declaración Forward de la clase utilizada en función de plantilla no es compilada por sonido metálico ++

class A; 

template <class T> 
void fun() { 
    A a; 
} 

class A { 
public: 
    A() { } 
}; 

int main() { 
    fun<int>(); 
    return 0; 
} 

g ++ 4,5 y g ++ 4.7 compila esto sin error. Pero clang ++ 3.2 (troncal) da este error:

main.cpp:5:6: error: variable has incomplete type 'A' 
    A a; 
    ^
main.cpp:1:7: note: forward declaration of 'A' 
class A; 
    ^

¿Qué compilador está en ese momento de acuerdo con el estándar C++?

+1

Como intenta crear un objeto de tipo 'A', el compilador debe conocer su tamaño, que no puede conocer sin haber visto la definición completa, así que clang estaría aquí (pero no tengo la referencia estándar) . –

+0

¿Hay algún cambio proporcionado por clang para compilar tal código? – Sashank

Respuesta

12

Which compiler is right then according to C++ standard?

Ambos son correctos. Este es un programa mal formado. El énfasis es mío:

N3290 14.6¶9
If a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is done, and if the completeness of that type affects whether or not the program is well-formed or affects the semantics of the program, the program is ill-formed; no diagnostic is required.

Ese sonido metálico ++ y otros compiladores emitir un diagnóstico que aquí hay una buena característica-a-han añadido, pero el diagnóstico no es obligatorio. Esa cláusula "el programa está mal formado, no se requiere ningún diagnóstico" le da libertad al desarrollador de compiladores para hacer casi cualquier cosa en tales circunstancias y seguir cumpliendo.

+0

¿por qué el programador ni siquiera está informado por g ++ de que algo anda mal? ¿debería ser así para que ambos compiladores estén correctos pero uno hace su trabajo y el segundo hace algo muy diferente? – scdmb

+1

La intención es permitir el procesamiento de plantillas perezosas. El estándar permite que las implementaciones difieran el análisis detallado hasta el punto en el que se crea una instancia de la plantilla. La clase 'A' se conoce en el momento de la instanciación, por lo que se compila.Todavía está mal formado porque otro archivo podría '#incluir' la definición de su plantilla, definir una clase completamente diferente' A', y crear un 'divertido diferente ()'. Esto no se enlazaría porque viola la regla de una definición (incluso si calificó 'fun' como' inline'). –

5

Clang es correcto, hasta donde yo sé. En función de su diversión, no conoce el tamaño de A, y dado que asigna una A, necesita saber su tamaño. En mi opinión, gcc es una forma de perdonar aquí.

+0

clang está siendo agradable al detectar el problema, pero la falta de un diagnóstico de gcc también es correcta. Ver mi respuesta para más detalles. –

0

compilador de Comeau no le gusta, sea:

"ComeauTest.c", line 5: error: incomplete type is not allowed 
    A a; 
    ^

Sin embargo mis intentos de encontrar pelos y señales en el C++ estándar fueron infructuosos. Parece oculto entre las líneas e interacciones de "punto de instanciación", "resolución de nombre". Los párrafos 14.6/8 y 14.6/9 de la norma de 2003 parecen pertinentes.

+0

no tengo la especificación a mano, pero sé que se agregó una regla (como resolución DR) para procesar su código "sin formato, sin necesidad de diagnóstico" en algún momento después de C++ 98 o C++ 03. se encuentra en el párrafo que habla de las definiciones de plantillas deficientes. –

1

clang++ está utilizando el comportamiento correcto, esto se describe en la sección 4.6/9 de la norma (n1905).


Templates 14.6/9 Name resolution

If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation.


Para poner las cosas en términos más simples; si el nombre es no depende de un parámetro de plantilla, debe estar en el ámbito donde se encuentra la definición; por lo tanto, deberá definir A antes de su definición de template<typename T> void fun().

+2

N1905 es un poco viejo. Es de 2005. N3291 fue (creo) el borrador final. –

Cuestiones relacionadas