template für Funktionszeiger mit versch. Rückgabetypen
-
Das ist ja total komisch...

Wo ist denn da die Logik?Mir solls egal sein. Hauptsache es klappt.
"Erstelle eine Variable f vom Typ FuncWithRet<int>::ptr"
...

Kann man Strukturen aus Typen bilden?
So eine art Sammlung von typen?
Geht das auch ohne Struktur? Ich brauche doch keine Sammlung von einem Element...
-
obbba schrieb:
Das ist ja total komisch...

Wo ist denn da die Logik?Sie ist da.
Man muss sich nur reindenken ... nur aufgrund Deiner anderen Fragen vermute ich, dass Dir noch das Wissen fehlt, den Gedanken dahinter zu verstehen, nicht böse gemeint.Ich versuch's trotzdem mal ...
Normale Funktionen haben Parameter und geben Werte zurück. Zum Beispiel folgende Funktion, die Identitätsfunktion (hat einen Parameter und gibt ihn unverändert zurück). Die mathematische Definition lautet: f(x) = x. In C++:
int f(int x) { return x; } // Aufruf: int zahl = f(42); // zahl == 42.In C++ geht das ganz analog auch für Typen (also nicht "ein Wert wird übergeben und zurückgegeben" sondern "ein Typ wird übergeben und zurückgegeben"), mit Templates:
template <typename T> struct F { typedef T Result; }; // "Aufruf": typedef F<int>::Result Typ; // Typ == int.Ich verwende sowas zur Zeit in einem Code, um abhängig vom Datentyp unterschiedliche Methoden aufzurufen (nein, *keine* Überladung ;-)).
Kann man Strukturen aus Typen bilden?
So eine art Sammlung von typen?Ja, klar. Das geht.
Geht das auch ohne Struktur? Ich brauche doch keine Sammlung von einem Element...
Nein das geht nicht. Wenn man so will, ist die von Simon gepostete Lösung ein Workaround, weil Typedefs mit Template-Parametern eben (noch) nicht funktionieren.
-
Für mich ist eine Struktur nichts, wo man was eingibt, die Struktur das verarbeitet und dann was ausgibt.
Für mich gibt es dazu Funktionen:template<typedef T> typename getTypePointer() {return T*};oder so ähnlich.
Das geht aber nicht, weil eine Funktion zur Laufzeit läuft und die Variablen-Typen da schon feststehen müssen. (In meinen Worten als Laie.)
In der Funktion als (precompile) Parameter für Typen (und anderes) kenne ich Templates schon.
//edit:
Das würde ich folgendermaßen interpretierentemplate <typename T> /*folgendes gibt es in verschiedenen Versionen für verschiedene Typen, "T" sei der Platzhalter für einen Typ.*/ struct F /*Es gebe einen Typ "F", der eine Sammlung von Variablen (bei c++ auch funktionen und Typen) darstellt*/ { typedef T Result; }; /*1. Komisch: eigtl.: "'Result' ist das gleiche wie 'T'" [=Anweisung] in dem Fall: "Es gebe einen Platzhalter für Typen mit dem Namen Result" [=Deklaration]*/ // "Aufruf": typedef F<int>::Result Typ; // Typ == int. /*Logisch: Weil in der Struktur eine Anweisung :confused: stand, wird der Parameter T, dem 'int' übergeben wurde in die Attribut-Variable 'result' geschrieben und dann (vor dem Compilieren) wird überall 'Typ' durch 'int' ersetzt. */
-
obbba schrieb:
Für mich ist eine Struktur nichts, wo man was eingibt, die Struktur das verarbeitet und dann was ausgibt.
Mathematisch gesehen ist sie das aber (ich vereinfache mal: eine mathematische Funktion hat Parameter und einen Rückgabewert). Es geht ja nicht um die Struktur an sich sondern um die Tatsache, dass es sich um ein Template handelt: Die Eingabe in diese Funktion (im *mathematischen* Sinn) sind die Template-Parameter -- und die Ausgabe ist ein Typedef, was üblicherweise 'Result' oder 'Type' oder so heißt.
/EDIT: Vergleiche http://de.wikipedia.org/wiki/Funktion_%28Mathematik%29
-
Ist ja Okay. Ich war nur ein bisschen gefrustet.

Du gibst ja selber zu, dass das nicht mathematisch korrekt ist.
-
obbba schrieb:
Du gibst ja selber zu, dass das nicht mathematisch korrekt ist.
Nein, das meinte ich nicht. Mathematisch gesehen ist das absolut korrekt. Lediglich meine Definition war ein wenig vereinfacht.
-
Man kann das so wie Konrad Rudolph machen, so eine Erklärung ist gut und richtig. Grundsätzlich denke ich, dass das Verständnis (=in Fleisch und Blut übergehen) dieses allgemeineren Funktionsbegriffes ungefähr 2/3 dessen ausmacht, was man für Template Metaprogrammierung braucht (ein weiters Viertel für High-Order Metafunktionen und den Rest um mit der barocken Syntax und einigen grundlegenden Defekten im Sprachdesign umzugehen). Das bedeutet gleichzeitig, das es auch das Schwerste an diesem Themenkomplex ist. Insofern sind verschiedene Ansätze nützlich, denn jeder denkt anders. Ich will hier mal eine weitere Variante bringen:
dein Ansatz wartemplate<typename T> typedef T(*PFkt)();das klappt so nicht, aber sicher hast du keine Schwierigkeiten
template<typename T> struct Foo;als eine Art Funktion anzusehen, man steckt einen Typ hinein, und bekommt ein struct heraus. Das Ganze passiert bereits beim Compilieren, aber wann etwas ausgewertet wird ist eigentlich nicht wesentlich, schließlich kann uns das auch bei ganz normalen Funktionsaufrufen passieren. Wenn etwas beim Programmablauf nicht variiert (und bei Typen ist das ja zum Beispiel so) ist es ja nicht weiter problematisch, das ganze schon beim Compilieren "auszurechnen". Unser Template ist also eine Funktion, gewissermaßen:
f(T) - und das schreiben wir in C++ auch fast genauso:
Foo<T>
Problematisch ist hier, dass der Wertebereich von f eingeschränkt ist, wir können nur structs zurückerhalten. Wie können wir dieses Problem umgehen und eine syntaktische Form erhalten, die uns für jede beliebige Kombination von Argumenten (die wir als Templateargumente schreiben woll) jedes beliebige Ding liefern kann?Betrachten wir einfach mal
struct X { int y; };was macht dann
X::y?
:: ist zunächst ein Operator wie jeder andere, und Operatoren sind im Grunde auch nichts weiter als Funktionen, nur die Syntax ist etwas anders als bei gewöhnlichen Funktionen
unser :: hat zwei Operanden (das ist jetzt keine korrekte Beschreibung nach der Sprachdefinition, es geht darum, wie es aussieht)
links steht irgenwas und rechts ein name
Ergebnis des "Operatoraufrufs" ist dasjenige, was unter dem rechts angegebenen Namen (hier: y) im Scope des linken Operanden (hier:
gefunden wird.
Dafür schreibe ich jetzt einfach mal:
g(X,y) <==> X::yWas ist dann Foo<T>::type ?
Das ist ein Aufruf der Operators :: mit dem Namen type und dem Ergebnis des Aufrufs Foo<T>
also quasi: g(f(T),type)
Das ist also nichts weiter als eine Verkettung von Funktionen also auch nur eine Funktion und wir können einfach substituieren:
h(T,type) <==> g(f(T),type) <==> Foo<T>::type
nun ist type hier aber eigentlich nur ein Vehikel, um um die Einschränkung des limitierten Wertebereichs von f herumzukommen, auf den konkreten Namen type kommt es nicht an. Hier setzt dann eine Konvention an: der zweite Parameter von h soll immer type sein, und wir erhalten eine Funktion, die nur noch von T abhängt:
i(T) <==> h(T,type) <==> g(f(T),type) <==> Foo<T>::type
-
obbba schrieb:
Das ist ja total komisch...

Wo ist denn da die Logik?...Ich glaube, Du siehst noch nicht "abstrakt genug" (auch nicht böse gemeint, ist reine Erfahrungssache).
In C++ handelt man eigentlich mit "Objekten" und "Typen". Letztere beschreiben abstrahiert die Eigenschaften der Objekte (sprich: "Was man mit ihnen anstellen kann").
Und zur Formulierung von Typen gibt's eben verschiedene Werkzeuge, die jeweils verschiedene Stärken haben: Klassen, Funktionen, primitive Datentypen, enums, ...
(BTW: "structs" sind auch einfach Klassen mit public (stat private) als Default)
Mit diesen Werkzeugen kann ich Typen nach meinem Bedarf modellieren und das bisweilen nicht nur auf einem Weg.
Ich sehe z.B. zwischenstruct doSomething { int operator()(int i); }; // und int doSomething(int i);nur einen Unterschied: Vom ersten Typ kann man andere Typen ableiten.
Ansonsten exakt dasselbe.... und eigentlich auch dasselbe wieclass myFunc { public: int doSomething(int i); };Jeweils geht es um einen "gedächtnislosen Funktionsaufruf", den man mit Objekten dieser Klasse durchführen kann.
Will man "Gedächtnis" haben, eigenen sich struct/class etwas besser (obwohl man mit statics auch der Funktion sowas "beibringen" könnte), Vererbung bietet das Werkzeug "Funktion" gar nicht.Kurz gesagt: Ich sehe keinen prinzipiellen Unterschied zwischen Funktionen und Klassen/structs: Sie sind nur Werkzeuge mit unterschiedlichen Stärken.
Gruß,
Simon2-
-
Simon2 schrieb:
obbba schrieb:
Das ist ja total komisch...

Wo ist denn da die Logik?...Ich glaube, Du siehst noch nicht "abstrakt genug" (auch nicht böse gemeint, ist reine Erfahrungssache).
In C++ handelt man eigentlich mit "Objekten" und "Typen". Letztere beschreiben abstrahiert die Eigenschaften der Objekte (sprich: "Was man mit ihnen anstellen kann").
Und zur Formulierung von Typen gibt's eben verschiedene Werkzeuge, die jeweils verschiedene Stärken haben: Klassen, Funktionen, primitive Datentypen, enums, ...
(BTW: "structs" sind auch einfach Klassen mit public (stat private) als Default)
Mit diesen Werkzeugen kann ich Typen nach meinem Bedarf modellieren und das bisweilen nicht nur auf einem Weg.
Ich sehe z.B. zwischenstruct doSomething { int operator()(int i); }; // und int doSomething(int i);nur einen Unterschied: Vom ersten Typ kann man andere Typen ableiten.
Ansonsten exakt dasselbe.... und eigentlich auch dasselbe wieclass myFunc { public: int doSomething(int i); };Jeweils geht es um einen "gedächtnislosen Funktionsaufruf", den man mit Objekten dieser Klasse durchführen kann.
Will man "Gedächtnis" haben, eigenen sich struct/class etwas besser (obwohl man mit statics auch der Funktion sowas "beibringen" könnte), Vererbung bietet das Werkzeug "Funktion" gar nicht.Kurz gesagt: Ich sehe keinen prinzipiellen Unterschied zwischen Funktionen und Klassen/structs: Sie sind nur Werkzeuge mit unterschiedlichen Stärken.
Gruß,
Simon2-
naja, einen unterschied gibt es schon zwischen funktionen und methoden.
beim methodenaufruf muss der this pointer ausfindig gemacht werden werden (mit ausnahme von static member funktionen)
das erlegdigt ja der compiler hinterrücks, aber fügt sozusagen einen zusätzlichen "push this" beim call einer membermethode an.
-
inp schrieb:
...
naja, einen unterschied gibt es schon zwischen funktionen und methoden.
...Ich will nicht leugnen, dass es Unterschiede gibt, aber eben auf einer "tieferen Abstraktionsebene" als die, auf die ich hinauswollte: Wir haben hier einen Typen, der einen einfachen Funktionsaufruf abbildet - in beiden Fällen.
"this" brauchst Du ja nur, wenn doch "Zustand" abgebildet werden soll (sprich, man mit einer static Funktion nicht mehr auskäme) ... und genau da habe ich auch die Grenze der Analogie gezogen. (Ja, ich weiß, der Compiler will ein this auch sonst haben, aber ich habe das static der Einfachheit halber weggelassen und bewusst der Klasse keine Attribute gegeben - dieses Lehrbeispiel ist wie alle nicht 100% unmißverständlich).
Gruß,
Simon2.
-
Simon2 schrieb:
inp schrieb:
...
naja, einen unterschied gibt es schon zwischen funktionen und methoden.
...Ich will nicht leugnen, dass es Unterschiede gibt, aber eben auf einer "tieferen Abstraktionsebene" als die, auf die ich hinauswollte: Wir haben hier einen Typen, der einen einfachen Funktionsaufruf abbildet - in beiden Fällen.
"this" brauchst Du ja nur, wenn doch "Zustand" abgebildet werden soll (sprich, man mit einer static Funktion nicht mehr auskäme) ... und genau da habe ich auch die Grenze der Analogie gezogen. (Ja, ich weiß, der Compiler will ein this auch sonst haben, aber ich habe das static der Einfachheit halber weggelassen und bewusst der Klasse keine Attribute gegeben - dieses Lehrbeispiel ist wie alle nicht 100% unmißverständlich).
Gruß,
Simon2.
das stimmt
