PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C++] Templates und Member-Funktionspointer


Gast
2008-03-04, 08:48:46
Ich habe eine Template Klasse, die einen Array kapselt. Für die darin gespeicherten Daten, möchte ich eine for_each( fooPtr ) Funktion implementieren, also ein Funktionspointer, der auf jedem Array Element ausgeführt werden kann.

Dies funktioniert auch schon, allerdings nicht für Memberfunktionen einer Klasse (und gerade dies ist wichtig). Ich habe gelesen, daß ich da irgendwie den Typ unterbringen muß, allerdings ist mir noch nicht klar, wie ich beliebige Typen von Memberfunktionspointern hier korrekt in die Signatur bekomme?

Man müßte die for_each Funktion wohl wieder als Template implementieren, wie ist mir das nur nicht klar.

So sieht es bei mir aktuell aus...

template<typename TYPE>
class Test
{
public:
typedef void (*fooPtr)(TYPE&);
inline void for_each( fooPtr foo ) {};
}

Jemand eine Idee, wie oder ob das machbar ist? Danke!

Corrail
2008-03-04, 09:23:20
http://www.sgi.com/tech/stl/mem_fun_t.html
http://www.boost.org/libs/bind/mem_fn.html

Gast
2008-03-04, 13:29:27
http://www.sgi.com/tech/stl/mem_fun_t.html
Klasse, danke.

Gast
2008-03-07, 08:44:44
Meine aktuelle Funktion sieht so aus:
myContainerObj.for_each<Class>( ClassPtr, &Class::MemPtr );

D.h. man muß stets den Template Parameter, den Pointer der Klasse, sowie den Funktionspointer angeben. Kann man dies verkürzen, wenn die Funktion zwar eine Memberfunktion, aber eben in der gleichen Klasse, wie der Aufruf ist? D.h. nicht in der gleichen Klasse, wie die Implementation meiner for_each Funktion, also wenn der ClassPtr "this" ist?

Kann man auch irgendwie auf einen nachfolgenden Stack statt auf eine Funktion zeigen? Das man dies evtl. wie eine "richtige" for-Schleife nutzen kann, in dem man sich einfach auf einen Block nach dem for_each statt auf eine Funktion bezieht?

danke

Gast
2008-03-10, 08:06:21
Gibt es evtl. eine Struktur, in dem man Funktionspointer auf Funktionen und Member (evtl. gar mit unterschiedlicher Signatur, aber weniger wichtig) kapseln kann. So daß man z.B. eine ganze Liste Funktionspointer auf Funktionen oder verschiedene Member kapseln kann und dann die einfach nur iterieren und auf jedem einen call machen muß?

Gast
2008-03-10, 16:08:53
boost::function

http://www.boost.org

Gast
2008-03-10, 16:20:40
Gibt es evtl. eine Struktur, in dem man Funktionspointer auf Funktionen und Member (evtl. gar mit unterschiedlicher Signatur, aber weniger wichtig) kapseln kann. So daß man z.B. eine ganze Liste Funktionspointer auf Funktionen oder verschiedene Member kapseln kann und dann die einfach nur iterieren und auf jedem einen call machen muß?
Such mal nach "Fast Delegates".

Gast
2008-04-01, 09:12:46
Such mal nach "Fast Delegates".Danke, das Ding ist ja der Hammer!

Hat das wirklich keine Nachteile? 20min, mit experimentiert und es funktioniert genial.

del_4901
2008-04-01, 12:15:13
Ich find die Fast Delegates doof, viel Code um nichts. Das ist in einer DinA4 Seite Standartkonform lösbar, ohne diesen ganzen Schmuß, den er da gemacht hat. Und wirklich langsam ist die "Alternative" auch nicht, dafür ist aber zugesichert, dass es in Zukunft schneller werden wird, und überall läuft.

Der große Nachteil von Funktoren ist, wenn man kein gutes Konzept hat, dann kommt Schmuß bei raus. Hat man ein gutes Konzept, braucht man auch meißt keine Funktoren mehr. Für alle Anderen Fälle ist es sehr hilfreich.

Gast
2008-04-01, 12:23:14
Wie geht denn das dann?

Ich möchte eine Liste mit Funktoren haben, die auf Member verschiedener Klassen zeigen können und dynamisch zur Laufzeit gefüllt (und wieder geleert) werden. Für mich war es immer ein Problem, daß der Member Pointer auf einen Klassentyp implementiert wird. D.h. Zugriffe auf Objekte verschiedener Klassen haben einen anderen Typ.

del_4901
2008-04-01, 12:28:20
Wie geht denn das dann?

Ich möchte eine Liste mit Funktoren haben, die auf Member verschiedener Klassen zeigen können und dynamisch zur Laufzeit gefüllt (und wieder geleert) werden. Für mich war es immer ein Problem, daß der Member Pointer auf einen Klassentyp implementiert wird. D.h. Zugriffe auf Objekte verschiedener Klassen haben einen anderen Typ.


Der Klassentyp ist (fast) scheiss egal, wenn er in C++ nicht (indirekt) mit zur Signatur gehören würde, könnte man das vernachlässigen. Meine Variante biegt das alles auf 0815 nichtMember-Funktoren und gut is. Und da ist es auch eigendlich scheiss egal was für ein Typ der this-Pointer hat. Interessiern dafür tut sich eh nur das Target. Und dafür das es Typsicher bleibt sorgt die Templatedefinition.

Gast
2008-04-01, 15:15:28
Der Klassentyp ist (fast) scheiss egal, wenn er in C++ nicht (indirekt) mit zur Signatur gehören würde, könnte man das vernachlässigen. Jo, das soll ja auch der Punkt sein, wo der ansetzt.

Meine Variante biegt das alles auf 0815 nichtMember-Funktoren und gut is. Und da ist es auch eigendlich scheiss egal was für ein Typ der this-Pointer hat. Interessiern dafür tut sich eh nur das Target. Und dafür das es Typsicher bleibt sorgt die Templatedefinition.Werden die Funktionen auf generische Typen gecastet oder was bedeutet dieses umbiegen auf 0815 nichtMember-Funktoren? Wie gesagt, ich möchte eigentlich nicht mehr als einen Memberpointer auf unterschiedliche Klassen irgendwie in einem Typ speichern können. Bisher war es eben immer das Problem, daß ich Calls auf unterschiedliche Klassen nicht in einer Liste zusammenfassen kann.

Ich überlege, gerade daß man doch eine Basisklasse mit einer pure virtual call Funktion bauen könnte, die durch ein Template zu einem sich implementierenden Kind wird? Dann hätte man Objekte eines Typs für Memberpointer und das Kind hält dann jeweils den Typ, aber er wird hinter einer Basisklasse verborgen. Das müßte doch gehen, oder?

del_4901
2008-04-01, 17:34:37
Werden die Funktionen auf generische Typen gecastet oder was bedeutet dieses umbiegen auf 0815 nichtMember-Funktoren? Wie gesagt, ich möchte eigentlich nicht mehr als einen Memberpointer auf unterschiedliche Klassen irgendwie in einem Typ speichern können. Bisher war es eben immer das Problem, daß ich Calls auf unterschiedliche Klassen nicht in einer Liste zusammenfassen kann.
Ich bau mir einfach eine Signatur mit this/self etc. Pointer, und erklär ihm in einem Template wie er damit umzugehen hat. (nämlich mit den Pointer 2 Member Operatoren)
Wenn der Compilerbauer nicht ganz aufn Kopp gefallen ist, kann er diesen hässlichen Aufruf hier und jetzt wegoptimieren. Da´s zusammenfassen in Listen kannst du auch mit Funktoren nicht, du musst nämlich für (ich steig jetzt mal auf Delegate um ...[typsicherer Funktor]) jedes Delegate die Signatur mit angeben. Das führt zwangsläufig zu signature coupling in diesem Fall ist das eine Form von literal logical coupling (lLc), und ist zu vermeiden. Zumindestens in C++ bei C# und Java würde man das mit unter Type Coupling einordnen. Da kann man jetzt aber streiten, wo das in C++ genau hingehört, das hängt auch von der Implementierungsart ab, weil es gibt ja sowas in C++ nicht von Haus aus.



Ich überlege, gerade daß man doch eine Basisklasse mit einer pure virtual call Funktion bauen könnte, die durch ein Template zu einem sich implementierenden Kind wird? Dann hätte man Objekte eines Typs für Memberpointer und das Kind hält dann jeweils den Typ, aber er wird hinter einer Basisklasse verborgen. Das müßte doch gehen, oder?
Ja normalerweise macht man das so oder so ähnlich. Meißtens brauchts dann nichtmahl mehr das Template. An der Stelle hier bekommst du übrigens unambigous type coupling (uTc), du musst nämlich den Typ der Basisklasse kennen. Das ist aber lLc vorzuziehen. Wenn alles Andere versagt, dann darf man zu Logischer Kopplung greifen.

ambigous Type coupling (aTc) ... der Aufrufer muss den Typ der Klasse kennen, die er aufrufen möchte.
unambigous type coupling (uTc) ... der Aufrufer muss den Typ der BasisKlasse kennen, die er aufrufen möchte.
algorithmic Logical coupling (aLc) ... Der Algorithmus des Aufrufers muss mit dem Algorithmus des Auzurufenden abgeglichen werden. (Das währe z.B Ver-/und Entschlüsselung)
literal logical coupling (lLc) ... der Aufgerufene handelt nach einem Literal, (Strings, Enums, Konstanten etc.) welches der Aufrufer festlegt. (Bsp: void (int, float, String) [so sehen meine C++ Delegates aus, und das ist eigentlich ein Spezialfall für Signature Coupling])


Das kann man jetzt noch weiter auftrödeln in static und dynamic coupling... am besten ihr kauft euch das Buch (http://www.amazon.com/Event-Based-Programming-Taking-Events-Limit/dp/1590596439)


llc kann man übrigens in aTc und das dann wiederum in uTc umformen. Nun könnte man zu dem schluss kommen, das man llc nie verwenden sollte, äh ja, Außnahme, der code ist überschaubar, es fuschen (Absprachen!!!... lange im Vorraus geplant) nicht mehrere Leute dran rum, und er ist leicht zu warten. Dann darf man lLc uTc vorziehen.

Gast
2008-04-02, 11:39:33
Vielen Dank, leider habe ich das teilweise nur begrenzt verstanden.
Ich bau mir einfach eine Signatur mit this/self etc. Pointer, und erklär ihm in einem Template wie er damit umzugehen hat. (nämlich mit den Pointer 2 Member Operatoren)
Wenn der Compilerbauer nicht ganz aufn Kopp gefallen ist, kann er diesen hässlichen Aufruf hier und jetzt wegoptimieren. Da´s zusammenfassen in Listen kannst du auch mit Funktoren nicht, du musst nämlich für (ich steig jetzt mal auf Delegate um ...[typsicherer Funktor]) jedes Delegate die Signatur mit angeben. Hast du ein Beispiel dafür und ein Dokument welches dies beschreibt? Die Methoden könnten was Parameter und Rückgabetyp angeht schon gleich sein (müßten sie sowieso), nur unterschiedliche Methodennamen und vorallem die Zusammenfassung unterschiedliche Klassen in einer Struktur sind wichtig. Meist Du mit der Template-Definition nur ein Funktion zum bauen einer derartigen Struktur oder gleich wieder ein Objekt? Denn dann hätte man ja für jede Templateimplementation ja wieder einen eigenen Typ.

Das führt zwangsläufig zu signature coupling in diesem Fall ist das eine Form von literal logical coupling (lLc), und ist zu vermeiden. Zumindestens in C++ bei C# und Java würde man das mit unter Type Coupling einordnen. Da kann man jetzt aber streiten, wo das in C++ genau hingehört, das hängt auch von der Implementierungsart ab, weil es gibt ja sowas in C++ nicht von Haus aus.

Ja normalerweise macht man das so oder so ähnlich. Meißtens brauchts dann nichtmahl mehr das Template. An der Stelle hier bekommst du übrigens unambigous type coupling (uTc), du musst nämlich den Typ der Basisklasse kennen. Das ist aber lLc vorzuziehen. Wenn alles Andere versagt, dann darf man zu Logischer Kopplung greifen.

ambigous Type coupling (aTc) ... der Aufrufer muss den Typ der Klasse kennen, die er aufrufen möchte.
unambigous type coupling (uTc) ... der Aufrufer muss den Typ der BasisKlasse kennen, die er aufrufen möchte.
algorithmic Logical coupling (aLc) ... Der Algorithmus des Aufrufers muss mit dem Algorithmus des Auzurufenden abgeglichen werden. (Das währe z.B Ver-/und Entschlüsselung)
literal logical coupling (lLc) ... der Aufgerufene handelt nach einem Literal, (Strings, Enums, Konstanten etc.) welches der Aufrufer festlegt. (Bsp: void (int, float, String) [so sehen meine C++ Delegates aus, und das ist eigentlich ein Spezialfall für Signature Coupling])


Das kann man jetzt noch weiter auftrödeln in static und dynamic coupling... am besten ihr kauft euch das Buch (http://www.amazon.com/Event-Based-Programming-Taking-Events-Limit/dp/1590596439)


llc kann man übrigens in aTc und das dann wiederum in uTc umformen. Nun könnte man zu dem schluss kommen, das man llc nie verwenden sollte, äh ja, Außnahme, der code ist überschaubar, es fuschen (Absprachen!!!... lange im Vorraus geplant) nicht mehrere Leute dran rum, und er ist leicht zu warten. Dann darf man lLc uTc vorziehen.Das Buch setze ich auf meine Liste, wobei es sich nicht auf C++ zu beziehen scheint, oder? Verstanden habe ich es bis hierhin aber leider nur begrenzt.

Ein Problem, daß ich bei meiner Idee mit dem BasisDelegate mit einer virtuellen call Funktion und einem Template von konkreten Implementationen übersehen habe, daß wenn ich die Implementation in den BasisTyp kopiere, ich die Daten des Kinds ja verliere. Also:
MyDelegate foo = MyDelegateImpl<Test>( testObjPtr, &Test::update );
foo.call();
also foo.call(); ruft MyDelegate::call() auf und nicht mehr MyDelegateImpl<Test>::call() wie wenn ich einfach einen Pointer caste. Aus uTc wird also wieder aTc (von der Bedeutung des Wortes ambiguous hätte ich ursprünglich erwartet, daß es andersherum heißt)? Gibt es da noch einen anderen Weg, als den Umweg über den Heap zu gehen? Vorallem weil Du sagtest, daß man dies auch ohne Templates lösen könne?

Im Prinzip etwas, was sich wie dieses fastdelegates Beispiel von oben verwenden läßt; also Stackobjekte eines Typs auf Memberfunktionen verschiedener Klasse, die man eben einfach kopieren und weiterreichen kann und am Ende auch in jedem Fall aufgeräumt wird... aber nur in standardkonform?

danke!

del_4901
2008-04-02, 19:23:02
Hast du ein Beispiel dafür und ein Dokument welches dies beschreibt? Die Methoden könnten was Parameter und Rückgabetyp angeht schon gleich sein (müßten sie sowieso), nur unterschiedliche Methodennamen und vorallem die Zusammenfassung unterschiedliche Klassen in einer Struktur sind wichtig. Meist Du mit der Template-Definition nur ein Funktion zum bauen einer derartigen Struktur oder gleich wieder ein Objekt? Denn dann hätte man ja für jede Templateimplementation ja wieder einen eigenen Typ.

Schön das jemand mal mitdenkt natürlich hast du Recht, ich war gestern warscheinlich zusehr aufm Schlauch. SC ist eine Form von Type Coupling (Ich hab total übersehen, das ein Template ja wieder einen Typ beschreibt.) Es ist aber weder uTc noch aTc weil für die Signatur eigendlich nur die Übergabeparameter, vllt. noch der Rückgabetyp (Ted nimmt den raus) beschrieben wird.


Das Buch setze ich auf meine Liste, wobei es sich nicht auf C++ zu beziehen scheint, oder? Verstanden habe ich es bis hierhin aber leider nur begrenzt.


Das ist egal ob nun C++ C# etc. letztenendes kann man das alles übertragen. Ted gibt auch Tips, wie man sich nicht verhaspelt.


Ein Problem, daß ich bei meiner Idee mit dem BasisDelegate mit einer virtuellen call Funktion und einem Template von konkreten Implementationen übersehen habe, daß wenn ich die Implementation in den BasisTyp kopiere, ich die Daten des Kinds ja verliere. Also:
MyDelegate foo = MyDelegateImpl<Test>( testObjPtr, &Test::update );
foo.call();
also foo.call(); ruft MyDelegate::call() auf und nicht mehr MyDelegateImpl<Test>::call() wie wenn ich einfach einen Pointer caste. Aus uTc wird also wieder aTc (von der Bedeutung des Wortes ambiguous hätte ich ursprünglich erwartet, daß es andersherum heißt)? Gibt es da noch einen anderen Weg, als den Umweg über den Heap zu gehen? Vorallem weil Du sagtest, daß man dies auch ohne Templates lösen könne?

Auf die Idee mit dem Basisdelegate bin ich auch schon gekommen, das ist aber eine Sackgasse. Die man mit Reflexion etwas dehnen kann, aber da wirds dann richtig kompliziert, und langsam. Und wie oben beschrieben, ist es nicht wirklich uTc oder aTc, eine Funktion ist nämlich nicht wirklich mit einem Typen in dem Sinne "vergleichbar", deswegen funktioniert die Umformung auch nicht.

Wie man das ohne Templates löst, kann ich dir jetzt nicht aus dem Stand sagen, weil mir dazu Hintergundwissen fehlt, was du genau machen möchtest.

Da gibt es fertige "Blaupausen" (http://www.amazon.de/Patterns-Elements-Reusable-Object-Oriented-Software/dp/0201633612 ... wenn du das noch nicht hast, dann ist das absolute Pflicht!)

Spontan könnte das "Strategy- oder Template Method-Pattern" passen. (wobei letzteres ohne Delegates funktioniert)


Im Prinzip etwas, was sich wie dieses fastdelegates Beispiel von oben verwenden läßt; also Stackobjekte eines Typs auf Memberfunktionen verschiedener Klasse, die man eben einfach kopieren und weiterreichen kann und am Ende auch in jedem Fall aufgeräumt wird... aber nur in standardkonform?

Schau mal hier: http://www.codeproject.com/KB/cpp/fd.aspx


danke!
np!

Gast
2008-04-03, 16:34:56
Danke!

Insbesondere das Beispiel auf Codeproject ist großartig. Auch wenn ich noch ein bißchen brauche um deren weiteren Evolutionsstufen zu verstehen, hat die erste Variante mir schon sehr weitergeholfen und verrichtet in leicht abgewandeltet Form bereits ihren Testdienst. Bin immer wieder überrascht, was für Zeug man mit Templates realisieren kann...