2016-04-16 3 views
4

Der folgende Code nicht kompiliert:Unterschied zwischen char [N] und char (&) [N] in Parameterliste

template <int N> 
void f(char[N]) {} 

int main() { 
    char buf[10]; 
    f(buf); 
} 

Wenn ich die char[N]-char (&)[N] ändern, es funktioniert. Also, was ist der Unterschied zwischen ihnen?

+1

Die erste Zeile ist die gleiche wie 'template void f (char *) {}' nach * Anpassung *, und dann gibt es keine Möglichkeit, 'N' aus dem Aufruf abzuleiten. Keine Anpassung gilt für 'char (&) [N]', daher kann 'N' abgeleitet werden. –

+0

@ M.M Genau. In Fällen, in denen der Template-Parameter einschließlich dieses nicht abgeleitet werden kann, kann er immer explizit angegeben werden. Vgl. Meine Antwort. –

+0

Warum nicht stattdessen ein std :: array als Argument verwenden? –

Antwort

2

offensichtlich sind Sie sich bewusst, dass char [N] ein Array ist und char (&)[N] ist ein Verweis auf eine char [N].

C-artige Arrays sind besonders, wenn sie als Argumente nach Wert übergeben werden. Das Array selbst wird nicht übergeben, aber eine Referenz ist.

Diese ‚Magie‘ ist ein historischer Nebeneffekt von C++ 's Entwicklung von C.

in diesen Tagen eine Reihe von Wert zu übergeben wir std::array<char, N> die kapseln den c-style-Array verwenden würden.

beachten Sie, dass char (&)[N] als Literaltyp behandelt wird und daher an constexpr Funktionen in Constexpr Kontext übergeben werden kann.

+0

* "Das Array selbst ist nicht übergeben, aber eine Referenz ist." * - Referenz ist ein Zeiger auf das erste Element. – LogicStuff

+0

@LogicStuff wird es bei Bedarf zu einem Pointer zerfallen, aber es ist eigentlich ein Verweis auf ein Objekt und trägt (vor allem für die Template-Ableitung) Typinformationen - einschließlich der Länge des Arrays. –

+2

"C-Style-Arrays sind besonders, wenn sie als Argumente nach Wert übergeben werden": Ja - weil sie einfach nie sind. –

6

Sie haben durch die Abwärtskompatibilität mit C. gebissen worden Wenn Sie eine Funktion wie erklären:

int f(char c[10]); 

erklären Sie eine Funktion, deren Argument ist vom Typ char *. Der Compiler verfällt den Argumenttyp für Sie. Das Problem ist:

int f(char c[5]); 

die gleiche Funktion erklärt. So funktionierte C, und C++ behielt es für die Kompatibilität bei.

Deklariert eine Funktion, deren Argument vom Typ "Verweis auf Array (Länge 10) von char" ist. C hatte keine Referenzen, daher ist keine Rückwärtskompatibilität erforderlich.

int f(char (&c)[5]); 

Deklariert eine verschiedene Funktion - mit einem anderen Argumente Typ.

+0

An sich geht Ihre Erklärung nicht so weit, dass Sie den Kompilierungsfehler erklären, bei dem es um die Ableitung von Template-Argumenten geht. –

2

Ich denke, die Reihenfolge der Ereignisse

  • ist der Compiler nicht Look für eine Funktion nimmt eine char[10] richtige, weil die Sprache nicht Arrays als Werte unterstützt vorbei.
  • Der Compiler sucht nach einer Funktion unter Referenz char[10] (und findet keine).
  • Der Compiler sucht nach einer Funktion, die einen Zeiger auf char nimmt. Dies ist der tatsächliche Argumenttyp nach dem Typ Anpassung, und findet keine.

Der letzte Punkt ist interessant, weil die Template-Funktion f tatsächlich einen Zeiger nimmt verkohlen, wie andere Plakate erklärt: der Index in der Erklärung überflüssig ist, und in einer Funktionsdeklaration f(char p[])p ist nicht vom Typ Array, aber vom Typ Zeiger auf char. Beachten Sie, dass sich dies anders als bei solchen Deklarationen anderswo (nicht als Funktionsparameter) unterscheidet, wobei ein Array wäre, wenn auch unvollständig.

Der Grund, dass der Compiler die Funktionsvorlage nicht instanziieren kann, ist nicht, dass sein Argumenttyp falsch ist: Er würde nach der Anpassung des Argumenttyps übereinstimmen. Der Grund ist einfach, dass der Vorlagenparameter N aus dem Argument nicht abgeleitet werden kann. Nach allem, für jeden N gäbe es einen anderen f: welchen sollte der Compiler nehmen ?? Nachdem das tatsächliche Argument buf an einen Zeiger auf sein erstes Element "angepasst" wurde, ist die Längeninformation im Argument verloren. (Ja, Compiler sind dumm.)

Die Längeninformationen wurden beibehalten, als Sie die Funktion als Verweis auf ein Array deklarierten.

Eine andere Möglichkeit ist die Template-Funktion explizit einfach zu instanziiert:

f<10>(buf); funktioniert.

Verwandte Themen