Ist das generisch?
-
Hui. Das ist nicht nur generisch, das ist sogar Meta-Programmierung. Bis auf die erste Zeile, die ist ein Syntaxfehler (aber ich nehme mal an, dass die sich durch nen Klickfehler oder so eingeschlichen hat).
Ich möchte allerdings anmerken, dass in diesem Fall wohl auch 10+5 zur Compilezeit berechnet würde...
Versuch mal, das hier zu verstehen:
#include <iostream> template<unsigned i> struct fib { static const long double val; }; template<unsigned i> const long double fib<i>::val = fib<i-1>::val + fib<i-2>::val; template<> const long double fib<0>::val = 0; template<> const long double fib<1>::val = 1; template<int i> struct fib_loop { static void run(); }; template<int i> void fib_loop<i>::run() { fib_loop<i-1>::run(); std::cout << i << ":\t" << fib<i>::val << std::endl; } template<> void fib_loop<-1>::run() { } int main() { std::cout.precision(0); std::cout.setf(std::ios::fixed); fib_loop<93>::run(); return 0; }
Es berechnet Fibonacci-Zahlen zur Compilezeit und ist so etwa das kanonische Beispiel für Meta-Programmierung.
-
Ich meine, berechnet der das während dem kompilieren?
Warum geschieht das bei deinem code (weils static ist?)
-
-
OK, dann will ich auf meta-programmierung hinaus... Kann da jemand Bücher empfehlen? @0xdeadbeef:
Ganz versteh ich das nicht: Warum so komplizier? Täte es eintemplate<unsigned i> struct fibonacci { enum{result=fibonacci<i-1>::result+fibonacci<i-2>::result}; }; template<> struct fibonacci<0> { enum{result=0}; }; template<> struct fibonacci<1> { enum{result=1}; };
Nicht auch?
/edit: Fehler entfernt...
-
ness schrieb:
Ich meine, berechnet der das während dem kompilieren?
Warum geschieht das bei deinem code (weils static ist?)ich versuchs mal zu erklären:
in c++ kann man soweit ich weis überall wo ein int steht, auch ein 1+1 stehen.
dh in einer enum darf einenum{ typ=1+1 };
existieren. Bislang nichts verwunderliches, der compiler muss halt, um den korrekten wert der enum rauszubekommen den Wert ausrechnen, das macht er aber nur, wenn man ihn dazu zwingt, dh typ muss man irgendwo benutzen.
nun kommen die templates dazu:
wenn der compiler eine template instanz erstellt, ersetzt er zuerst die template platzhalter mit dem neuen typ/wert, dh://aus template<int i> struct test{ enum{Value=i}; }; //wird struct test_5{ enum{Value=5}; };
und wenn an der stelle halt eine rechnung steht, wird der compiler das wieder ausrechnen.
so funktioniert auch die rekursion. der compiler ersetzt den templateparameter und merkt, dass da eine neue template instanz erwartet wird, also erstellt er auch für diese den code. Ist in dieser neuerstellten Klasse wieder so ein template enthalten, erstellt er auch dafür eine instanz, usw.
Im falle deines Add5 wird "result" von der Klasse gefordert.
wenn er versucht result abzufragen, merkt der compiler, dass er die klasse noch nicht erstellt hat->er erstellt sie. versucht er da wieder result abzufragen wird er mit demselben problem konfrontiert. irgendwann landet er beid er abbruchbedingung, und da rollt sich das ganze dann wieder auf, der compiler rechnet dann von hinten nach vorne 5+1+1+1+1...+1, denn die oben von mir erklärten enumregeln zwingen ihn dazu.
-
Also ist meine Lösung richtig??? Und das 2.? Kannst du mir meine Fragen dazu beantworten? Und was passiert wenn man sowas macht? (Bezieht sich auf mein erstes)
using namespace std; cout<<"Zahl eingeben!"; int i; cin>>i; cout<<add5<i>;
/edit: Aber deine Lösung ist dann also nicht zur kompilier-zeit berechnet?
-
versuch mal dieses code stück zu kompilieren....
dann sollte dir in etwa folgende meldung entgegenschlagen:error: non-constant `i' cannot be used as template argument
warum ist auch klar: die templates werde vom compiler zur compile-zeit instaziiert. der wert von i ist allerdings erst zur laufzeit bekannt.
-
/edit: Aber deine Lösung ist dann also nicht zur kompilier-zeit berechnet?
doch, static const verhält sich genauso, mit enums ist es aber einfacher zu erklären ;).
dein letztes codebeispiel kann aber nicht funktionieren, da template parameter compiletime konstant sein müssen, dh die eingabe müsste schon zur compilezeit erfolgen, bzw der compiler müsste wissen, welche zahl eingegeben wird,und da das nicht geht, sagt der compiler: nö,das mach ich nicht.
ist auch irgendwie verständlich, da es ja nur für deinen fall 233-1 verschiedene eingabemöglichkeiten gäbe, ergo der compiler für 233-1 Klassen code generieren müsste,und die auswahl der Klasse im sourcecode je nachdem welche eingabe stattfand dürfte jeden berechnungsvorteil effektiv zunichte machen.
-
kleine frage: wie kommst du auf 2³³-1 möglichkeiten? imho sollten das eher 2³² sein...
-
rechne den wert aller 32 bits zusammen
-
hm? versteh ich jetzt nicht ganz...es sind 32 bit.. also 32 mal die unterscheidung zwischen 0 und 1 => 2³² mögliche kombinationen => 2³² verschiedene zahlen => 2³² verschiedene instanzen der template klasse... klar, die summe diese 2³² zahlen ist 2³³-1, aber was hat das damit zu tun?
-
es hat damit was zu tun, dass 233-1 verschiedene werte in den template parameter eingesetzt werden können, und für jeden wert im template müsste ne Klasse generiert werden->233-1 verschiedene Klassen.
-
Meine Lösung ist also richtig, aber die Variablen müssen zur kompilezeit bekannt sein und deshalb kann das letzte nicht gehen...
-
genau. und vergiss nicht: floating points gehen auch nicht
-
Jup, und dass man in einer enumeration nicht zu einem Vorzeichenbehafteten typ casten kann, hab ich auch grad rausgefunden...