Pergunta sobre clang++, c++, forward-declaration, templates, g++ – A declaração de avanço da classe usada na função template não é compilada pelo clang ++

12

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 e g ++ 4.7 compila isso sem erro. Mas o clang ++ 3.2 (tronco) dá este erro:

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

Qual compilador está certo, de acordo com o padrão C ++?

Existe algum parâmetro fornecido pelo clang para compilar esse código? Sashank
Desde que você tenta criar um objeto do tipoA o compilador tem que saber o seu tamanho que ele não pode saber sem ter visto a definição completa, então o clang estaria aqui (mas eu não tenho a referência std). Benjamin Bannier

Sua resposta

4   a resposta
5

até onde eu sei. Na sua função divertida, você não sabe o tamanho de A, e desde que você alocou um A, você precisa saber seu tamanho. Na minha opinião, gcc é maneira de perdoar aqui.

O clang está sendo bom ao detectar o problema, mas a falta de um diagnóstico do gcc também está correta. Veja minha resposta para detalhes. David Hammen
0

O compilador de Comeau também não gosta:

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

No entanto, minhas tentativas de encontrar capítulos e versos no padrão C ++ foram infrutíferas. Parece escondido entre as linhas e interações de "ponto de instanciação", "resolução de nomes". Os parágrafos 14.6 / 8 e 14.6 / 9 da norma de 2003 parecem relevantes.

Eu não tenho a especificação na mão, mas eu sei que uma regra foi adicionada (como uma resolução de DR) para tornar seu código "mal formado; sem diagnóstico necessário" algum tempo após c + + 98 ou c + + 03. Ele está localizado no parágrafo que fala sobre definições de modelo malformadas. Johannes Schaub - litb
1

clang++ está usando o comportamento correto, isso é descrito na seção4.6/9 do padrão (n1905).

Templates 14.6/9 Name resolution

Se um nome não depende de um template-parameter (como definido em14.6.2), uma declaração (ou conjunto de declarações) para esse nome deve estar no escopo no ponto em que o nome aparece na definição do modelo; o nome está vinculado à declaração (ou declarações) encontradas nesse ponto e essa ligação não é afetada por declarações visíveis no momento da instanciação.

Colocar as coisas em termos mais simples; se o nome énão dependente de um parâmetro de modelo, ele deve estar no escopo onde a definição é encontrada; portanto, você precisará definirA antes de sua definição detemplate<typename T> void fun ().

O N1905 é um pouco antigo. É de 2005. N3291 foi (eu acho) o rascunho final. David Hammen
12

Ambos estão corretos. Este é um programa mal formado. Ênfase minha:

N3290 14.6¶9
Se um tipo usado em um nome não dependente estiver incompleto no ponto em que um modelo é definido, mas está completo no ponto em que uma instanciação é feita, e se a integridade desse tipo afeta se o programa está ou não bem formado ou afeta a semântica do programa,o programa está mal formado; nenhum diagnóstico é necessário.

Esse clang ++ e outros compiladores fazem um diagnóstico aqui é um recurso adicional legal, mas um diagnóstico não é obrigatório. Essa cláusula "o programa é mal-formado; nenhum diagnóstico é necessário" permite que um desenvolvedor livre de compilador reine para fazer praticamente qualquer coisa em tais circunstâncias e ainda ser compatível.

A intenção é permitir o processamento de modelos preguiçosos. O padrão permite que implementações adiem a análise detalhada ao ponto em que um modelo é instanciado. ClasseA é conhecido no ponto de instanciação, por isso compila. Ainda é mal formado porque outro arquivo poderia#include sua definição de modelo, defina uma classe completamente diferenteAe crie um diferentefun<int>(). Isso falharia ao vincular porque viola a única regra de definição (mesmo se você se qualificoufun Comoinline). David Hammen
por que então o programador nem sequer é informado pelo g ++ que algo está errado? Deveria ser assim que ambos os compiladores estivessem corretos, mas um faz o seu trabalho e o segundo faz algo muito diferente? scdmb

Perguntas relacionadas