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.

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top