Domanda

Qualcuno può spiegare perché il seguente codice non si compila (su 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);
}

Il messaggio che ricevo è:

jjj.cpp: nella funzione 'int main ()':
jjj.cpp: 10: 'xx :: a' non è un membro statico di 'struct x'
JJJ.CPP: 10: nessuna funzione di corrispondenza per chiamata a 'x :: x ()'
jjj.cpp: 1: i candidati sono: x :: x (const x &)
JJJ.CPP: 5: X :: X (X :: State) `

Questo cattivo codice o un bug del compilatore?

Problema risolto da Neil+Konrad. Vedi i commenti alla risposta di Neil di seguito.

È stato utile?

Soluzione

X(X::A);

si vede la dichiarazione della funzione ASA. Se vuoi davvero questo codice, usa:

(X)(X::A);

Altri suggerimenti

Hai dimenticato il nome della variabile nella tua definizione:

int main()
{
   X my_x(X::A);
}

Il tuo codice confonde il compilatore perché sintatticamente non può distinguerlo da una dichiarazione di funzione (ritorno X e passando X::A come argomento). In caso di dubbio, il compilatore C ++ si esplode sempre a favore di una dichiarazione.

La soluzione è introdurre parentesi ridondanti attorno al X Poiché il compilatore proibisce le parentesi attorno ai tipi (invece di costruire chiamate ecc.):

(X(X::A));

Solo per renderlo cristallino cosa succede. Guarda questo esempio

int main() {
    float a = 0;
    {
        int(a); // no-op?
        a = 1;
    }
    cout << a;
}

Cosa uscirà? Bene, uscirà 0. Il int(a) di sopra può essere analizzato in due modi diversi:

  • Lanciare su int e scartare il risultato
  • Dichiarare una variabile chiamata a. Ma ignora le parentesi attorno all'identificatore.

Il compilatore, quando una situazione del genere appare in cui un cast in stile funzione viene utilizzato in una dichiarazione e sembra anche una dichiarazione, lo prenderà sempre come una dichiarazione. Quando non può essere sintatticamente una dichiarazione (il compilatore esaminerà l'intera linea per determinarlo), sarà considerato un'espressione. Quindi stiamo assegnando al interno a Sopra, lasciando l'esterno a a zero.

Ora, il tuo caso è esattamente questo. Stai cercando (accidentalmente) di dichiarare un identificatore chiamato A All'interno di una classe chiamata X:

X (X::A); // parsed as X X::A;

Il compilatore continua a gemere su un costruttore predefinito non dichiarato, perché lo statico, come presuppone che sia, viene costruito predefinito. Ma anche se avessi un costruttore predefinito per X, ovviamente è ancora sbagliato perché nessuno dei due A è un membro statico di X, né una statica di X può essere definita/dichiarata a blocchi.

Ce la puoi fare non Sembra una dichiarazione facendo diverse cose. Innanzitutto, puoi pareggiare l'intera espressione, il che non fa più sembrare una dichiarazione. O semplicemente paren il tipo che viene scelto. Entrambe queste disambiguazioni sono state menzionate in altre risposte:

(X(X::A)); (X)(X::A)

C'è un'ambiguità simile, ma distinta quando si tenta di dichiarare effettivamente un oggetto. Guarda questo esempio:

int main() {
    float a = 0;
    int b(int(a)); // object or function?
}

Perché int(a) può essere sia la dichiarazione di un parametro chiamato a E la conversione esplicita (cast) della variabile float a un INT, il compilatore decide di nuovo che questa è una dichiarazione. Pertanto, ci capita di dichiarare una funzione chiamata b, che prende un argomento intero e restituisce un numero intero. Esistono diverse possibilità su come disambiguarlo, in base alla disambiguazione di cui sopra:

int b((int(a))); int b((int)a);

Dovresti dichiarare un oggetto come

X x(X::A);

Bug nel tuo codice.

Entrambe queste due righe funzionano per me:

X obj(X::A);
X obj2 = X(X::A);

Come sottolinea Neil Butterworth, X(X::A) viene trattato come una dichiarazione di funzione. Se vuoi davvero un oggetto anonimo, (X)(X::A) costruirà un oggetto X e lo eliminerà immediatamente.

Potresti, ovviamente, fare qualcosa del genere:

int main()
{
    // code
    {
    X temp(X::A);
    }
    // more code
}

Questo sarebbe più leggibile e sostanzialmente avrebbe lo stesso effetto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top