La declaración directa de clase utilizada en la función de plantilla no está compilada por clang ++

Existe este código:

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 compilan esto sin error. Pero clang++ 3.2 (tronco) 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 es correcto entonces de acuerdo con el estándar C++?

preguntado el 12 de junio de 12 a las 10:06

Dado que intenta crear un objeto de tipo A el compilador tiene que saber su tamaño, que no puede saber sin haber visto la definición completa, por lo que clang estaría justo aquí (pero no tengo la referencia estándar). -

¿Hay algún interruptor proporcionado por clang para compilar dicho código? -

4 Respuestas

¿Qué compilador es correcto entonces de acuerdo con el estándar C++?

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

N3290 14.6¶9
Si un tipo utilizado en un nombre no dependiente está incompleto en el punto en el que se define una plantilla, pero está completo en el punto en el que se realiza una creación de instancias, y si la integridad de ese tipo afecta si el programa está bien o no. formado o afecta la semántica del programa, el programa está mal formado; no se requiere diagnóstico.

Que clang++ y otros compiladores emitan un diagnóstico aquí es una característica añadida que es bueno tener, pero un diagnóstico no es obligatorio. Esa cláusula "el programa está mal formado; no se requiere diagnóstico" le da al desarrollador del compilador rienda suelta para hacer casi cualquier cosa en tales circunstancias y aún así cumplir.

Respondido el 12 de junio de 12 a las 13:06

¿Por qué entonces g ++ ni siquiera informa al programador que algo anda mal? ¿debería ser para que ambos compiladores estén correctos pero uno hace su trabajo y el segundo hace algo muy diferente? - scdmb

La intención es permitir el procesamiento diferido de plantillas. El estándar permite que las implementaciones difieran el análisis detallado hasta el punto en el que se instancia una plantilla. Clase A se conoce en el punto de creación de instancias, por lo que compila. Todavía está mal formado porque otro archivo podría #include su definición de plantilla, defina una clase completamente diferente Ay crear una diferente fun<int>(). Esto no se vincularía porque viola la regla de una definición (incluso si calificó fun as inline). - david hamen

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

Respondido el 12 de junio de 12 a las 10:06

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

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

Si un nombre no depende de un parámetro de plantilla (como se define en 14.6.2), una declaración (o un conjunto de declaraciones) para ese nombre estará dentro del alcance en el punto donde el nombre aparece en la definición de la plantilla; el nombre está vinculado a la declaración (o declaraciones) encontradas en ese punto y este vínculo no se ve afectado por las declaraciones que son visibles en el punto de instanciación.


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

Respondido el 12 de junio de 12 a las 12:06

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

Al compilador de Comeau tampoco le gusta:

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

Sin embargo, mis intentos de encontrar capítulos y versos en el estándar C++ fueron infructuosos. Parece escondido entre las líneas y las interacciones de "punto de creación de instancias", "resolución de nombres". Los párrafos 14.6/8 y 14.6/9 de la norma de 2003 parecen relevantes.

Respondido el 12 de junio de 12 a las 11:06

No tengo la especificación a mano, pero sé que se agregó una regla (como una resolución DR) para hacer que su código esté "mal formado; no se requiere diagnóstico" en algún momento después de c ++ 98 o c ++ 03. se encuentra en el párrafo que habla de definiciones de plantillas mal formadas. - Johannes Schaub - litb

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.