Ich habe eine kurze Frage zu Punkt 48 in Scott Meyers "Effective C ++". Ich verstehe einfach nicht den Code aus dem Buch kopiert,
%Vor%Warum muss ich enum in der Vorlagenprogrammierung verwenden? Gibt es einen alternativen Weg, dies zu tun? Danke für die Hilfe im Voraus.
Sie könnten static const int
auch verwenden:
Das sollte auch in Ordnung sein. Das Ergebnis ist in beiden Fällen gleich.
Oder Sie können eine vorhandene Klassenvorlage verwenden, z. B. std::integral_constant
(in C ++ 11 nur) wie:
Ich sehe, dass die anderen Antworten die alternativen Ansätze gut abdecken, aber niemand erklärt, warum enum
(oder static const int
) erforderlich ist.
Betrachten Sie zunächst das folgende Nicht-Template-Äquivalent:
%Vor%Sie sollten es leicht verstehen können. Es ist jedoch ein Nachteil, dass der Wert des Faktors zur Laufzeit berechnet wird, d. H. Nach dem Ausführen des Programms führt der Compiler die rekursiven Funktionsaufrufe und Berechnungen aus.
Die Idee des Template-Ansatzes besteht darin, zur Kompilierungszeit die gleichen Berechnungen durchzuführen und das Ergebnis in die resultierende ausführbare Datei einzufügen. Mit anderen Worten, das vorgestellte Beispiel löst etwas Ähnliches auf:
%Vor%Aber um das zu erreichen, müssen Sie den Compiler dazu bringen, die Berechnungen auszuführen. Und um das zu tun, müssen Sie das Ergebnis irgendwo speichern lassen.
Der enum
ist genau dafür da. Ich werde versuchen, das zu erklären, indem ich darauf hinwies, was dort nicht funktionieren würde.
Wenn Sie versucht haben, ein reguläres int
zu verwenden, würde es nicht funktionieren, weil ein nicht-statisches Element wie int
nur in einem instanziierten Objekt sinnvoll ist. Und Sie können ihm keinen Wert zuweisen, sondern das in einem Konstruktor. Eine einfache int
wird nicht funktionieren.
Sie benötigen etwas, auf das in einer uninstantiierten Klasse zugegriffen werden könnte. Sie könnten static int
ausprobieren, aber es funktioniert immer noch nicht. clang
würde Ihnen eine ziemlich einfache Beschreibung des Problems geben:
Wenn Sie diese Definitionen tatsächlich außer Linie bringen, wird der Code kompiliert, aber es ergibt sich zwei 0
s. Das liegt daran, dass diese Form die Berechnung von Werten für die Initialisierung des Programms verzögert und die korrekte Reihenfolge nicht garantiert. Es ist wahrscheinlich, dass ein Factorial<n-1>::value
s vor der Berechnung erhalten wurde und somit 0
zurückgegeben wurde. Außerdem ist es immer noch nicht das, was wir wirklich wollen.
Schließlich, wenn Sie static const int
dort setzen, wird es wie erwartet funktionieren. Das liegt daran, dass static const
zur Kompilierzeit berechnet werden muss, und genau das wollen wir. Lassen Sie uns den Code erneut eingeben:
Zuerst instanziert Factorial<5>
; static const int
erzwingt, dass der Compiler seinen Wert zum Zeitpunkt des Compilers berechnet. Effektiv instanziiert es den Typ Factorial<4>
, wenn er einen anderen Wert berechnen muss. Und das geht so lange, bis es Factorial<0>
erreicht, wo der Wert ohne weitere Instanziierungen berechnet werden kann.
Also, das war der alternative Weg und die Erklärung. Ich hoffe, es war zumindest ein bisschen hilfreich, den Code zu verstehen.
Sie können sich diese Art von Vorlagen als Ersatz für die rekursive Funktion vorstellen, die ich zu Beginn geschrieben habe. Sie ersetzen nur:
return x;
mit static const int value = ...
, f(x-1)
mit t<x-1>::value
, if (n == 0)
mit der Spezialisierung struct Factorial<0>
. Und für das enum
selbst, wie bereits erwähnt, wurde es im Beispiel verwendet, um dasselbe Verhalten wie static const int
durchzusetzen. Es ist so, weil alle enum
-Werte zur Kompilierungszeit bekannt sein müssen, so dass jeder angeforderte Wert zur Kompilierungszeit berechnet werden muss.
Sie können static const int
verwenden, wie Nawaz sagt. Ich vermute, der Grund, warum Scott Myers eine Enumeration benutzt, ist, dass die Compiler-Unterstützung für die In-Class-Initialisierung von statischen Const-Ganzzahlen ein bisschen eingeschränkt war, als er das Buch schrieb. Also ein Enum war eine sicherere Option.
Tags und Links c++ effective-c++