2015-09-23 13 views
7

Ich habe auf Array-Konzepte in C++ auffrischen, wenn ich auf diese Frage kam: Return an array in c++Syntax für in C eine Array-Referenz Rückkehr ++

Jemand antwortete, diese Erklärung mit:

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

Was kann ich Ich verstehe nicht, ist die [3] nach der schließenden Klammer. Ich habe noch nie eine Funktionsdeklaration gesehen, die so aussah. Ich verstehe den Rest der Syntax, aber ich verstehe nicht besonders, wie das [3] funktioniert, weil es nach dem Funktionsnamen ist. Ich entschuldige mich im Voraus, wenn ich etwas Einfaches übersehe. Ich habe auch versucht, die Spezifikation für Funktionsdeklarationen zu betrachten, aber ich sah nichts, was ich mit der Subscript-Syntax verbinden konnte. Also, wie ist das möglich?

+1

Da K & R Sadisten sind . – orlp

+0

http://cdecl.org/. C-Deklaratorsyntax kann "Spaß" sein. –

+1

Sobald Sie es bekommen, schreiben Sie nie so schreckliche Sache in einem echten Code. – kebs

Antwort

5

Die Funktion kehrt eine Referenz auf ein Array von int der Größe 3 und den [3] Teil nach der Funktion tatsächlich die Größe des Arrays als Referenz zurückgeführt werden.

Diese obskure Syntax stammt aus der seltsamen Syntax der Array-Deklaration, die Sie tun, wie:

int arr[3]; //real but weird 

Die Sprache viel einfacher gewesen wäre, wenn es diese Stelle hat:

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

weil Größe 3 ist Teil vom Typ arr, es macht also viel mehr Sinn, wenn alle Teile auf der linken Seite des Variablennamens erscheinen, genau wie beim Schreiben:

unsigned int a; 

Sie nicht schreiben:

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

Während also die Sprache mit unsigned int das Richtige tut, tut es eine sehr seltsame Sache mit int[3].

Nun zurück zur Funktionsdeklaration kommen, wäre die Funktion viel besser gewesen, wenn es so erklärt:

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

nur, wenn es auf der linken Seite des Variablennamen alle Teile hatte. Aber da es das nicht tun (dh der Sprache erfordert Sie die Größe auf der äußersten rechten Seite nach dem Variablennamen schreiben), können Sie mit dieser seltsamen Signatur am Ende:

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

Beachten Sie, dass, wie auch die Parameter wird seltsam.


Aber Sie es mit einem typedef wie vereinfachen kann:

typedef int array_type[3]; 

array_type& f(array_type& arr); 

so viel besser aussieht. Jetzt sieht nur die typedef seltsam aus.

Mit C++ 11, können Sie sogar eine bessere typedef schreiben:

using array_type = int[3]; 

array_type& f(array_type& arr); 

, die als diese so nah ist (wenn Sie array_type als int[3] visualisieren):

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

Hoffnung, die hilft .

+1

Vielen Dank! Das macht jetzt alles Sinn. – Izodine

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

Lassen Sie uns von innen gehen. Der (int (&arr)[3]) Teil bedeutet, dass die Funktion einen Verweis auf ein int Array von 3 Elementen als Parameter verwendet. Dies ist das gleiche arr, das zurückgegeben wird.

Nun, der Rest der Syntax besagt, dass die Funktion einen Verweis auf ein Array von 3 Ints zurückgeben sollte. f ist der Name der Funktion. int &f() würde bedeuten, dass Sie einen Verweis auf eine int zurückgeben, aber Sie müssen ein Array der festen Größe zurückgeben, daher sollten Sie die [3] hinzufügen Die Klammern um die &f(...) werden verwendet, weil Sie in C++ schreiben Sie die Größe des Arrays nach der Variablen Name, nicht nach dem Typnamen, wie Nawaz in seiner Antwort erklärt. Wenn Sie diese Klammern weglassen, interpretiert der Compiler f als ein Array von Referenzen, wie in int & f[3].

2

Nun, lesen Sie diese article über C-Geschichte, von seinem Schöpfer Dennis M. Ritchie.

Sieht aus wie diese Syntax wir von B bekam, durch C bis C++ ...

Ich glaube, auf diese Weise mehrere Variablen von einem gewissen „Grundtyp“ zu deklarieren ist eine Wurzel dieser seltsamen Syntax:

int a, *b, c[3]; 

So a ist nur int ist b Zeiger auf int und c wird Array von int ...

Wenn diese * und [3] würden einen Teil der Typdefinition keiner Variablendefinition sein - dann würden wir 3 Zeilen benötigen, dies zu schreiben:


Es gibt zwei gute Ressourcen auf SO C page zu lernen, wie man solche Konstruktionen zu analysieren:

cdecl ist ein wenig versagt - weil Referenzen nicht Teil C sind - so wollen wir versuchen, mit The Clockwise/Spiral Rule for parsing C declarations.

int (&f(int (&arr)[3]))[3] 
  1. arr -> arr
  2. &arr -> arr ist Referenz
  3. (&arr) -> arr ist reference - umgebende () nicht wirklich etwas ändern
  4. (&arr)[3] -> arr wird Bezug auf Array der Größe 3
  5. int (&arr)[3] -> arr Bezug auf Array der Größe 3 des Typs int

Next:

  1. f -> f
  2. f(int (&arr)[3]) -> f ist Funktion, die arr nimmt, die ist ...
  3. &f(int (&arr)[3]) -> f ist Funktion, die arr nimmt, die ... ist, und Rückkehrreferenz
  4. (&f(int (&arr)[3]))[3] -> f ist ANL Funktion nimmt, das ist, ..., und der Bezug auf Array der Größe zurückkehr 3
  5. int (&f(int (&arr)[3]))[3] -> f Funktion unter arr ist, die sich auf Array der Größe 3 des Typs int ist, und die Bezugnahme auf Array der Größe 3 vom Typ int Rückkehr

natürlich - dieser Code wird ersetzt mit, zumindest für mich, viel einfache Version zu lesen:

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

Das macht Sinn. Danke für die ausführliche Antwort! Die Spiralregel wird sehr nützlich sein. – Izodine