Enum c ++ não reconhecido corretamente pelo compilador
-
22-08-2019 - |
Pergunta
Alguém pode explicar por que o código a seguir não compila (no G ++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-49))?
struct X {
public:
enum State { A, B, C };
X(State s) {}
};
int main()
{
X(X::A);
}
A mensagem que recebi é:
jjj.cpp: na função 'int main ()':
jjj.cpp: 10: 'xx :: a' não é um membro estático de 'struct x'
jjj.cpp: 10: Nenhuma função de correspondência para chamada 'x :: x ()'
jjj.cpp: 1: Os candidatos são: x :: x (const x &)
jjj.cpp: 5: x :: x (x :: estado) `
Isso é um código ruim ou um bug do compilador?
Problema resolvido por Neil+Konrad. Veja os comentários para a resposta de Neil abaixo.
Solução
X(X::A);
está sendo visto a declaração da função ASA. Se você realmente deseja este código, use:
(X)(X::A);
Outras dicas
Você esqueceu o nome da variável em sua definição:
int main()
{
X my_x(X::A);
}
Seu código confunde o compilador porque, sintaticamente, ele não pode distinguir isso de uma declaração de função (retornando X
e passando X::A
como um argumento). Em caso de dúvida, o compilador C ++ sempre se desambia em favor de uma declaração.
A solução é introduzir parênteses redundantes em torno do X
Como o compilador proíbe parênteses em torno dos tipos (em oposição às chamadas de construto etc.):
(X(X::A));
Só para deixar claro o que acontece. Veja este exemplo
int main() {
float a = 0;
{
int(a); // no-op?
a = 1;
}
cout << a;
}
O que será lançado? Bem, será lançado 0
. o int(a)
de acima pode ser analisado de duas maneiras diferentes:
- Fundido para int e descartar o resultado
- Declarar uma variável chamada
a
. Mas ignore os parênteses ao redor do identificador.
O compilador, quando essa situação aparece em que um elenco no estilo de função é usado em uma declaração e parece uma declaração também, sempre a considerará uma declaração. Quando não pode ser sintaticamente uma declaração (o compilador analisará toda a linha para determinar isso), será considerado uma expressão. Assim, estamos atribuindo ao interior a
acima, deixando o exterior a
a zero.
Agora, seu caso é exatamente isso. Você está tentando (acidentalmente) declarar um identificador chamado A
Dentro de uma aula chamada X
:
X (X::A); // parsed as X X::A;
O compilador passa a gemer sobre um construtor padrão não declarado, porque a estática, como assume que é, é construída padrão. Mas mesmo se você tivesse um construtor padrão para x, é claro que ainda está errado porque também não A
é um membro estático de x, nem uma estática de x pode ser definida/declarada no escopo do bloco.
Você consegue não Parece uma declaração fazendo várias coisas. Primeiro, você pode parenar toda a expressão, o que faz com que não pareça mais uma declaração. Ou apenas paren o tipo que é lançado. Ambas as desambiguações foram mencionadas em outras respostas:
(X(X::A)); (X)(X::A)
Há uma ambiguidade semelhante, mas distinta, quando você tenta realmente declarar um objeto. Veja este exemplo:
int main() {
float a = 0;
int b(int(a)); // object or function?
}
Porque int(a)
pode ser a declaração de um parâmetro chamado a
e a conversão explícita (elenco) da variável flutuante para um INT, o compilador decide novamente que isso é uma declaração. Assim, por acaso declaramos uma função chamada b
, que pega um argumento inteiro e retorna um número inteiro. Existem várias possibilidades de como desambiguar isso, com base na desambiguação acima:
int b((int(a))); int b((int)a);
Você deve declarar um objeto como
X x(X::A);
Bug em seu código.
Qualquer uma dessas duas linhas funciona para mim:
X obj(X::A);
X obj2 = X(X::A);
Como Neil Butterworth aponta, X(X::A)
está sendo tratado como uma declaração de função. Se você realmente quer um objeto anônimo, (X)(X::A)
construirá um objeto X e o excluirá imediatamente.
Você poderia, é claro, fazer algo assim:
int main()
{
// code
{
X temp(X::A);
}
// more code
}
Isso seria mais legível e basicamente teria o mesmo efeito.