2015-09-23 26 views
7

Sono stato spazzolatura su concetti di array in C++, quando mi sono imbattuto in questa domanda: Return an array in c++Sintassi per la restituzione di un riferimento ad array in C++

Qualcuno ha risposto con questa dichiarazione:

int (&f(int (&arr)[3]))[3] 

quello che posso sembra che capisca [3] dopo la parentesi di chiusura. Non ho mai visto una dichiarazione di funzione simile a questa. Capisco il resto della sintassi, ma non capisco in particolare come funziona [3] perché è dopo il nome della funzione. Mi scuso in anticipo se trascuro qualcosa di semplice. Ho anche provato a guardare le specifiche per le dichiarazioni di funzioni, ma non ho visto nulla di collegato che potessi collegare alla sintassi del pedice. Quindi, come è possibile?

+1

Perché K & R sono sadici . – orlp

+0

http://cdecl.org/. La sintassi del dichiaratore C può essere "divertente". –

+1

Una volta ottenuto, per favore non scrivere mai una cosa così orribile in un codice di vita reale. – kebs

risposta

5

La funzione restituisce un riferimento a una matrice di int di dimensioni 3 e la parte [3] dopo la funzione effettivamente la dimensione della matrice da restituire come riferimento.

Questa sintassi oscura deriva dalla strana sintassi della dichiarazione di matrice, che si fa come:

int arr[3]; //real but weird 

Il linguaggio sarebbe stato molto più semplice se avesse questo, invece:

int[3] arr; //hypothetical but better and simpler 

perché la dimensione 3 è parte del tipo di arr, quindi ha molto più senso se tutte le parti compaiono sul lato sinistro del nome della variabile, nello stesso modo in cui scrivete:

unsigned int a; 

È Dont write:

unsigned a int; //analogous to : int a [3]; 

Così, mentre la lingua fa la cosa giusta con unsigned int, fa una cosa molto strana con int[3].

Ora tornando alla dichiarazione di funzione, la funzione sarebbe stato molto meglio se viene dichiarata come:

int[3]& f(int[3]& arr); //hypothetical 

solo se aveva tutte le parti sul lato sinistro del nome-variabile. Ma dal momento che non lo fa (cioè il linguaggio richiede di scrivere le dimensioni sul lato più a destra dopo il nome della variabile), si finisce con questa firma strano:

int (&f(int (&arr)[3])[3]; //real 

Si noti che come anche il parametro diventa strano


Ma è possibile semplificare con un typedef come:

typedef int array_type[3]; 

array_type& f(array_type& arr); 

Che sembra molto meglio. Ora solo il typedef sembra strano.

Con C++ 11, è possibile scrivere anche un typedef meglio:

using array_type = int[3]; 

array_type& f(array_type& arr); 

che è il più vicino questo (se si visualizza array_type come int[3]):

int[3]& f(int[3]& arr); //hypothetical 

Speranza che aiuta .

+1

Grazie mille! Tutto ciò ha senso ora. – Izodine

1
int (&f (int (&arr)[3]))[3] 
{ 
    return arr; 
} 

Andiamo dall'interno. La parte (int (&arr)[3]) significa che la funzione prende come riferimento un array int di 3 elementi come parametro. Questo è lo stesso arr che viene restituito.

Ora, il resto della sintassi dice che la funzione dovrebbe restituire un riferimento a un array di 3 pollici. f è il nome della funzione. int &f() significherebbe restituire un riferimento a un int, ma è necessario restituire un array della dimensione fissa, quindi è necessario aggiungere [3] Le parentesi attorno allo &f(...) vengono utilizzate perché in C++ si scrive la dimensione dell'array dopo la variabile nome, non dopo il nome del tipo, come spiega Nawaz nella sua risposta. Se si omette questa parentesi, il compilatore interpreterà f come una matrice di riferimenti, come in int & f[3].

2

Bene, leggi questo article sulla storia di C, dal suo creatore Dennis M. Ritchie.

Sembra che questa sintassi abbiamo ottenuto da B, attraverso C al C++ ...

Credo, in questo modo di dichiarare diverse variabili di un certo "tipo di base" è una radice di questa strana sintassi:

int a, *b, c[3]; 

Così a è solo int, b è puntatore a int e c è array di int ...

Se questi * e [3] sarebbe parte di non definizione del tipo di definizione della variabile - allora avremmo bisogno di 3 linee di scrivere questo:


Ci sono due buone risorse su SO C page per imparare come analizzare tali costruzioni:

cdecl sta venendo a mancare un po '- perché i riferimenti non sono parte di C - così proviamo con The Clockwise/Spiral Rule for parsing C declarations.

int (&f(int (&arr)[3]))[3] 
  1. arr -> arr
  2. &arr -> arr è riferimento
  3. (&arr) -> arr è riferimento - circostante () non cambia davvero nulla
  4. (&arr)[3] -> arr fa riferimento ad array di lunghezza 3
  5. int (&arr)[3] -> arr fa riferimento ad array di dimensione 3 di tipo int

successivo:

  1. f -> f
  2. f(int (&arr)[3]) -> f è funzione che prende arr, che è ...
  3. &f(int (&arr)[3]) -> f è la funzione che prende arr, che è ..., e restituisce il riferimento
  4. (&f(int (&arr)[3]))[3] -> f è funzione prendendo arr, che è ... e ritornando riferimento ad array di lunghezza 3
  5. int (&f(int (&arr)[3]))[3] -> f è funzione tenendo arr, che fa riferimento ad array di dimensione 3 di tipo int, e tornando riferimento ad array di dimensione 3 di tipo int

Naturalmente - questo codice è sostituito, almeno per me, molto più facile da leggere la versione:

using int3 = int[3]; 
int3& f(int3& arr); 
+0

Questo ha senso. Grazie per la risposta dettagliata! La regola della spirale sarà molto utile. – Izodine