Beispiel
#include <iostream>
template <int N> struct Factorial
{
enum { val = Factorial<N-1>::val * N };
};
template<>
struct Factorial<0>
{
enum { val = 1 };
};
int main()
{
// Note this value is generated at compile time.
// Also note that most compilers have a limit on the depth of the recursion available.
std::cout << Factorial<4>::val << "\n";
}
Das hat ein bisschen Spaß gemacht, war aber nicht sehr praktisch.
Um den zweiten Teil der Frage zu beantworten:
Ist diese Tatsache in der Praxis nützlich?
Kurze Antwort: Art von.
Lange Antwort: Ja, aber nur, wenn Sie ein Vorlagendämon sind.
Es ist wirklich sehr schwierig (obwohl machbar), eine gute Programmierung mit Vorlagen-Metaprogrammierung zu erzielen, die für andere sehr nützlich ist (dh eine Bibliothek). Um zu helfen, hat sogar MPL aka (Meta Programming Library) zu steigern . Versuchen Sie jedoch, einen Compilerfehler in Ihrem Vorlagencode zu debuggen, und Sie werden eine lange, harte Fahrt erleben.
Aber ein gutes praktisches Beispiel dafür, wie es für etwas Nützliches verwendet wird:
Scott Meyers hat Erweiterungen der C ++ - Sprache (ich verwende den Begriff locker) unter Verwendung der Vorlagenfunktionen verwendet. Sie können hier ‚über seine Arbeit lesen Enforcing Code Ausführung ‘
Ich habe eine Turingmaschine in C ++ 11 gemacht. Von C ++ 11 hinzugefügte Funktionen sind für die Turing-Maschine in der Tat nicht von Bedeutung. Es werden lediglich Regellisten beliebiger Länge mit variablen Vorlagen anstelle der perversen Makro-Metaprogrammierung bereitgestellt :). Die Namen für die Bedingungen werden verwendet, um ein Diagramm auf stdout auszugeben. Ich habe diesen Code entfernt, um das Beispiel kurz zu halten.
quelle
" C ++ - Vorlagen sind vollständig " bietet eine Implementierung einer Turing-Maschine in Vorlagen ... die nicht trivial ist und den Punkt auf sehr direkte Weise beweist. Natürlich ist es auch nicht sehr nützlich!
quelle
Mein C ++ ist ein bisschen verrostet, daher ist das vielleicht nicht perfekt, aber es ist nah.
Der Punkt ist zu demonstrieren, dass der Compiler die rekursive Definition vollständig auswertet, bis er eine Antwort erreicht.
quelle
Um ein nicht triviales Beispiel zu geben: http://gitorious.org/metatrace , ein C ++ - Compile Time Ray Tracer.
Beachten Sie, dass C ++ 0x eine Nicht-Template-Funktion zur Kompilierungszeit und zur vollständigen Vervollständigung in Form von Folgendem hinzufügt
constexpr
:Sie können
constexpr
-expression überall dort verwenden , wo Sie Konstanten für die Kompilierungszeit benötigen, aber Sie können auchconstexpr
-functions mit Nicht-const-Parametern aufrufen .Eine coole Sache ist, dass dies endlich die Kompilierzeit-Gleitkomma-Mathematik ermöglicht, obwohl der Standard ausdrücklich festlegt, dass die Kompilierzeit-Gleitkomma-Arithmetik nicht mit der Laufzeit-Gleitkomma-Arithmetik übereinstimmen muss:
quelle
Das Buch Modernes C ++ - Design - Generisches Programmieren und Designmuster von Andrei Alexandrescu ist der beste Ort, um praktische Erfahrungen mit nützlichen und leistungsstarken generischen Programmiermustern zu sammeln.
quelle
Das faktorielle Beispiel zeigt nicht, dass Vorlagen vollständig sind, sondern zeigt, dass sie die primitive Rekursion unterstützen. Der einfachste Weg, um zu zeigen, dass Vorlagen vollständig sind, ist die Church-Turing-These, bei der entweder eine Turing-Maschine (chaotisch und etwas sinnlos) oder die drei Regeln (app, abs var) des untypisierten Lambda-Kalküls implementiert werden. Letzteres ist viel einfacher und weitaus interessanter.
Was diskutiert wird, ist eine äußerst nützliche Funktion, wenn Sie verstehen, dass C ++ - Vorlagen eine reine funktionale Programmierung zur Kompilierungszeit ermöglichen. Dieser Formalismus ist ausdrucksstark, leistungsstark und elegant, aber auch sehr kompliziert zu schreiben, wenn Sie wenig Erfahrung haben. Beachten Sie auch, wie viele Leute feststellen, dass das Erhalten von Code mit starken Vorlagen oft einen großen Aufwand erfordert: Dies ist genau der Fall bei (reinen) Funktionssprachen, die das Kompilieren erschweren, aber überraschenderweise Code liefern, der kein Debuggen erfordert.
quelle
Ich denke, es heißt Template-Meta-Programmierung .
quelle
Nun, hier ist eine Turing Machine-Implementierung zur Kompilierungszeit, auf der ein 4-Status-Biber mit 2 Symbolen ausgeführt wird
Ideone Proof Run: https://ideone.com/MvBU3Z
Erläuterung: http://victorkomarov.blogspot.ru/2016/03/compile-time-turing-machine.html
Github mit weiteren Beispielen: https://github.com/fnz/CTTM
quelle
Sie können diesen Artikel von Dr. Dobbs über eine FFT-Implementierung mit Vorlagen lesen, die ich nicht so trivial finde. Der Hauptpunkt besteht darin, dem Compiler eine bessere Optimierung als bei Nicht-Template-Implementierungen zu ermöglichen, da der FFT-Algorithmus viele Konstanten verwendet (z. B. Sin-Tabellen).
Teil I.
Teil II
quelle
Es macht auch Spaß darauf hinzuweisen, dass es sich um eine rein funktionale Sprache handelt, die jedoch kaum zu debuggen ist. Wenn Sie sich James Post ansehen, werden Sie sehen, was ich damit meine, dass er funktionsfähig ist. Im Allgemeinen ist es nicht die nützlichste Funktion von C ++. Es war nicht dafür ausgelegt. Es ist etwas, das entdeckt wurde.
quelle
Dies kann nützlich sein, wenn Sie zumindest theoretisch Konstanten zur Kompilierungszeit berechnen möchten. Schauen Sie sich die Metaprogrammierung von Vorlagen an .
quelle
Ein Beispiel, das einigermaßen nützlich ist, ist eine Verhältnisklasse. Es gibt einige Varianten. Das Erfassen des D == 0-Falls ist bei teilweisen Überlastungen ziemlich einfach. Die eigentliche Berechnung besteht in der Berechnung der GCD von N und D und der Kompilierungszeit. Dies ist wichtig, wenn Sie diese Verhältnisse für Berechnungen zur Kompilierungszeit verwenden.
Beispiel: Wenn Sie Zentimeter (5) * Kilometer (5) berechnen, multiplizieren Sie zur Kompilierungszeit das Verhältnis <1.100> und das Verhältnis <1000,1>. Um einen Überlauf zu vermeiden, möchten Sie ein Verhältnis <10,1> anstelle eines Verhältnisses <1000,100>.
quelle
Eine Turing-Maschine ist Turing-vollständig, aber das bedeutet nicht, dass Sie eine für den Produktionscode verwenden möchten.
Der Versuch, mit Vorlagen etwas nicht Triviales zu tun, ist meiner Erfahrung nach chaotisch, hässlich und sinnlos. Sie haben keine Möglichkeit, Ihren "Code" zu "debuggen". Fehlermeldungen zur Kompilierungszeit sind kryptisch und befinden sich normalerweise an den unwahrscheinlichsten Stellen. Sie können dieselben Leistungsvorteile auf unterschiedliche Weise erzielen. (Hinweis: 4! = 24). Schlimmer noch, Ihr Code ist für den durchschnittlichen C ++ - Programmierer unverständlich und wird wahrscheinlich nicht portierbar sein, da die aktuellen Compiler ein breites Maß an Unterstützung bieten.
Vorlagen eignen sich hervorragend für die generische Codegenerierung (Containerklassen, Klassenumbrüche, Mix-Ins), aber nein - meiner Meinung nach ist die Vollständigkeit von Vorlagen in der Praxis NICHT NÜTZLICH .
quelle
Nur ein weiteres Beispiel dafür, wie man nicht programmiert:
Post at C ++ - Vorlagen sind vollständig
quelle
K17<Depth+1>::x * 5
.