Perché il C ++ ci consente di racchiudere il nome della variabile tra parentesi quando si dichiara una variabile?


84

Ad esempio una dichiarazione come quella:

int (x) = 0;

O anche quello:

int (((x))) = 0;

Mi sono imbattuto in questo perché nel mio codice mi è capitato di avere un frammento simile al seguente:

struct B
{
};

struct C
{
  C (B *) {}
  void f () {};
};

int main()
{
  B *y;
  C (y);
}

Ovviamente volevo costruire un oggetto Cche poi avrebbe fatto qualcosa di utile nel suo distruttore. Tuttavia, come accade il compilatore tratta C (y);come una dichiarazione di variabile ycon tipo Ce quindi stampa un errore sulla yridefinizione. La cosa interessante è che se lo scrivo come C (y).f ()o come qualcosa di simile C (static_cast<B*> (y))verrà compilato come previsto. La migliore soluzione alternativa moderna è quella di utilizzare {}nella chiamata al costruttore, ovviamente.

Quindi, come ho capito dopo, è possibile dichiarare variabili come int (x) = 0;o anche int (((x))) = 0;ma non ho mai visto nessuno usare effettivamente dichiarazioni come questa. Quindi mi interessa: qual è lo scopo di tale possibilità perché per ora vedo che crea solo il caso simile al famigerato "analisi più irritante" e non aggiunge nulla di utile?


Lo "scopo" della possibilità è probabilmente quello di semplificare il parser.
molbdnilo


1
@GSerg Divertente come il testo della mia domanda risponde alla domanda dalla seconda risposta nella tua domanda collegata, poiché fornisco l'esempio in cui consentire tali dichiarazioni porta a risultati inaspettati :)
Predelnik


caduto in questa trappola: non sapevo che il mutex fosse commentato e quindi ha scritto accidentalmente la dichiarazione di parentesi errata. // std :: mutex std :: unique_lock <std :: mutex> (m_mutex);
Servire Laurijssen il

Risposte:


80

Raggruppamento.

Come esempio particolare, considera che puoi dichiarare una variabile di tipo funzione come

int f(int);

Ora, come dichiareresti un puntatore a una cosa del genere?

int *f(int);

No, non funziona! Questo viene interpretato come una funzione di ritorno int*. È necessario aggiungere le parentesi per farlo analizzare nel modo giusto:

int (*f)(int);

La stessa cosa con gli array:

int *x[5];   // array of five int*
int (*x)[5]; // pointer to array of five int

13
E per completare la risposta: rifiutare il caso particolare di cui il richiedente sta chiedendo richiederebbe una regola extra per casi speciali. L'attuale definizione di come ()lavorare in un tipo è uniforme in tutto il tipo.
Joseph Mansfield

Quindi il caso speciale si applica all'analisi più fastidiosa. Questo perché la sintassi per inizializzare le variabili con gli argomenti del costruttore è stata aggiunta successivamente (in fretta immagino?).
AnArrayOfFunctions

1
@FISOCPP Bene. . sì. C ++ è venuto dopo C.. .
iheanyi

Questa risposta si applica allo stesso modo al C, non solo al C ++?
kdbanman

" variabile di tipo funzione " cosa? !!
curioso

17

In genere è consentito usare le parentesi in tali dichiarazioni perché la dichiarazione, dal punto di vista sintattico, è sempre così:

<front type> <specification>;

Ad esempio, nella seguente dichiarazione:

int* p[2];

Il "tipo di fronte" è int(non int*) e la "specifica" è * p[2].

La regola è che puoi usare qualsiasi numero di parentesi secondo necessità nella parte "specifica" perché a volte è inevitabile disambiguare. Per esempio:

int* p[2]; // array of 2 pointers to int; same as int (*p[2]);
int (*p)[2]; // pointer to an array of 2 ints

Il puntatore a un array è un caso raro, tuttavia la stessa situazione che hai con un puntatore a funzione:

int (*func(int)); // declares a function returning int*
int (*func)(int); // declares a pointer to function returning int

Questa è la risposta diretta alla tua domanda. Se la tua domanda riguarda l'affermazione del tipo C(y), allora:

  • Metti le parentesi attorno all'intera espressione (C(y))e otterrai ciò che desideri
  • Questa dichiarazione non fa altro che creare un oggetto temporaneo, che cessa di vivere al termine di questa istruzione (spero che questo sia ciò che intendevi fare).

1
Come ho detto, inizialmente stava facendo qualcosa nel distruttore, immagino che sia una cosa abbastanza standard quando hai un certo numero di funzioni di "concatenamento" per impostare alcuni parametri e poi fare tutto il lavoro nel distruttore. Grazie per un'altra soluzione alternativa, immagino che la scrittura {}sia la più valida dopo tutto.
Predelnik

4
cerca di evitare di inventare la tua grammatica e usa quella fornita nello standard. <front-type> <specification>è fuorviante e sbagliato. La grammatica è<declaration-specifier> <declarator>
Steve Cox

Hai ragione: non ho esaminato lo standard, ho solo ripetuto la regola dalla mia testa. In realtà in C ++ 11 il ruolo di <declaration-specifier>può essere giocato anche da autoparola chiave, quindi non è nemmeno sempre un tipo.
Ethouris

@Pravasi Meet: Se hai modificato la parte del mio post e cambiato i nomi nello schema di sintassi dato, per favore cambia anche i nomi nelle 3 righe sottostanti di conseguenza. Altrimenti ci sono ancora vecchi nomi "front type" e "specificazione" e quindi il post non ha alcun senso.
Ethouris
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.