Function in Liste (tList) Speichern

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

Bob

Betreff: Function in Liste (tList) Speichern

BeitragMi, Apr 06, 2011 12:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo zusammen.
Ist es möglich eine Function in einer Liste zu speichern?

Code: [AUSKLAPPEN]

Function Test()
   Print "dies ist ein test"
End Function

Local vArFunc() = Test  'funktioniert
varfunc

Local L:TList = New TList
l.AddLast Test  'funktioniert nicht
' Compile Error: Unable to convert from 'Int()' to 'Object'

Er soll an den Spielen teilnehmen bis er spielend stirbt. MCP - TRON

Lord Stweccys

BeitragMi, Apr 06, 2011 14:06
Antworten mit Zitat
Benutzer-Profile anzeigen
Vielleicht geht es mit ein bisschen Assembler-Magie...

ToeB

BeitragMi, Apr 06, 2011 14:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich glaub es sollte mit "l.AddLast Object( Test )" gehen...
Edit : Sry geht ja um Functions-Zeiger... Habs mal mit Function Test:Object() probiert aber geht auch nicht...


mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!

Moep

BeitragMi, Apr 06, 2011 14:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Speicher die Funktion in einer Klasse, ist zwar minimal umständlicher, wäre aber eine Lösung des Problem.


mfg
Hardstyle Schleichwerbung:
http://www.youtube.com/user/Hackepeter42

Achtung: Suchtgefahr!
moep123.ohost.de

Bob

BeitragMi, Apr 06, 2011 14:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
Speicher die Funktion in einer Klasse, ist zwar minimal umständlicher, wäre aber eine Lösung des Problem.


Werd ich mal versuchen. Danke.
Weiterhin hab ich dann das noch (nachträglich) gefunden.

https://www.blitzforum.de/foru...cf31d8ab0a
Er soll an den Spielen teilnehmen bis er spielend stirbt. MCP - TRON

BlitzMoritz

BeitragMi, Apr 06, 2011 20:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Interessantes Problem und gute Idee von Moep, übrigens gar nicht so kompliziert, hab's 'mal ausprobiert.
BlitzMax: [AUSKLAPPEN]
Type TFuncClass
Method Func() Abstract
End Type

Type Test1 Extends TFuncClass
Method Func()
Print "dies ist ein test"
End Method
End Type
Local VarTest1:Test1 = New Test1

Type Test2 Extends TFuncClass
Method Func()
Print "dies ist ein anderer test"
End Method
End Type
Local VarTest2:Test2 = New Test2

Local FuncClassList:TList = CreateList()
ListAddLast(FuncClassList, VarTest1)
ListAddLast(FuncClassList, VarTest2)

For Local FuncClass:TFuncClass = EachIn FuncClassList
FuncClass.Func()
Next

Das sollte genau das sein, was Bob sucht.
Edit: Hab' erst danach Bobs Link angeschaut, das sind natürlich auch gute Alternativen...

ToeB

BeitragMi, Apr 06, 2011 20:41
Antworten mit Zitat
Benutzer-Profile anzeigen
BlitzMax: [AUSKLAPPEN]
Type TFunc
Field FuncPtr:Object()

Function Create:TFunc( _FuncPtr:Object() )
Local tmp:TFunc = New TFunc
tmp.FuncPtr = _FuncPtr
Return tmp
End Function
End Type

Local List:TList = CreateList( )
Local Test1:TFunc = TFunc.Create( func1 )
List.AddLast( Test1 )

Local Test2:TFunc = TFunc.Create( func2 )
List.AddLast( Test2 )


For Local tmp:TFunc = EachIn List
tmp.FuncPtr( )
Next

Function func1:Object( )
Print "Funktion 1"
End Function

Function func2:Object( )
Print "Funktion 2"
End Function


Ich glaub das passt eher als es über Type Vererbung zu machen...


mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!
 

n-Halbleiter

BeitragDo, Apr 07, 2011 23:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Und dazu noch ein System von mir, vor etwas längerer Zeit geschrieben. Der folgende Quelltext kann simpel per Import eingebunden werden. Er benutzt TMaps (BRL.Map), um die Daten zu speichern. Ich habe hier schonmal ein paar Worte zum Code verloren und möchte jetzt noch etwas hinzufügen: Es ist nicht unbedingt eine optimierte Lösung, aber sie funktioniert. Die Abfrage erfolgt durch Methoden des Types "TFPtrWrapper". Da BMax in der Hinsicht Parametertypen, -anzahl und Rückgabewerten leider etwas eingeschränkt ist (und ich, als ich den Code geschrieben habe, noch nicht so vertraut mit Funktionspointern war), muss für jeden Typ Funktion, die gespeichert werden soll, ein Type angelegt werden und entsprechend gecastet werden. Ich hoffe trotzdem, dass der Code hilfreich ist.

BlitzMax: [AUSKLAPPEN]
Import BRL.Blitz
Import BRL.Map

Type TFPtrWrapper

Field _rgNameSpaces:TMap
Field _NullNameSpace:TNameSpace
Field _CurrentNameSpace:TNameSpace

'Constructors & Destructor
Function Create:TFPtrWrapper()
Return New TFPtrWrapper.Init()
End Function

Method Init:TFPtrWrapper()
Self._rgNameSpaces=CreateMap()
Self._NullNameSpace=TNameSpace.Create("")
Self._CurrentNameSpace=Self._NullNameSpace
Self.FinishNameSpace()
Return Self
End Method

'Interfacing
Method RegisterNameSpace(rgchName:String)
Self._CurrentNameSpace=TNameSpace.Create(rgchName)
End Method

Method FinishNameSpace()
Self._rgNameSpaces.Insert(Self._CurrentNameSpace.Name().ToLower(),Self._CurrentNameSpace)
Self._CurrentNameSpace=Self._NullNameSpace
End Method

Method RestoreNameSpace(rgchName:String)
Self._CurrentNameSpace=TNameSpace(Self._rgNameSpaces.ValueForKey(rgchName.ToLower()))
End Method

Method LookUpNameSpace:TNameSpace(rgchName:String)
Local Obj:Object=Self._rgNameSpaces.ValueForKey(rgchName.ToLower())
Return TNameSpace(Obj)
End Method

Method HasNameSpace:Byte(rgchName:String)
Return Self._rgNameSpaces.Contains(rgchName.ToLower())
End Method

Method AddFPtr(FPtr:TFPtr)
Self._CurrentNameSpace.AddFPtr(FPtr)
End Method

Method GetFPtr:TFPtr(rgchName:String)
Local rgch:String[]=rgchName.Split("::")
Local NameSpace:TNameSpace,FPtr:TFPtr
NameSpace=Self.LookUpNameSpace(rgch[0])
If NameSpace=Null Then RuntimeError "Could not find namespace "+rgch[0]
FPtr=NameSpace.GetPtr(rgch[1])
If FPtr=Null Then RuntimeError "Could not find FPtr "+rgch[1]
Return FPtr
End Method

Method List()
Local NameSpace:TNameSpace
Local FPtr:TFPtr
Print ""
Print "FPtrWrapper lists all namespaces:"
For NameSpace=EachIn Self._rgNameSpaces.Values()
Print "--> Namespace: "+NameSpace.Name()
For FPtr=EachIn NameSpace._rgFPtr.Values()
Print " --> FPtr: "+FPtr.Name()
Next
Next
Print "Done!"
Print ""
End Method

End Type

Type TNameSpace

Field _rgchName:String
Field _rgFPtr:TMap

'Constructors & Destructor
Function Create:TNameSpace(rgchName:String)
Return New TNameSpace.Init(rgchName)
End Function

Method Init:TNameSpace(rgchName:String)
Self._rgFPtr=CreateMap()
Self._rgchName=rgchName
Return Self
End Method

'Interfacing
Method AddFPtr(FPtr:TFptr)
Self._rgFPtr.Insert(FPtr.Name().ToLower(),FPtr)
End Method

Method GetPtr:TFPtr(rgchName:String)
Return TFPtr(Self._rgFPtr.ValueForKey(rgchName.ToLower()))
End Method

Method FreePtr(rgchName:String)
Self._rgFPtr.Remove(rgchName.ToLower())
End Method

'Getters & Setters
Method Name:String()
Return Self._rgchName
End Method

End Type

Type TFPtr Abstract

Const C_cType:Byte=5
Const C_sType_VoidVoid:Byte=0
Const C_sType_VoidObj:Byte=1
Const C_sType_ObjVoid:Byte=2
Const C_sType_ObjObj:Byte=3
Const C_sType_Void2Obj:Byte=4

Field _rgchName:String
Field _sType:Byte

'Getters & Setters
Method Name:String()
Return Self._rgchName
End Method

' Method Execute() Abstract

Method GetType:Byte()
Return Self._sType
End Method

End Type

Type TVoidVoidPtr Extends TFPtr

Field _Ptr()

'Constructors & Destructor
Method New()
Self._sType=TFptr.C_sType_VoidVoid
End Method

'Interfacing
Method Execute()
Self._Ptr()
End Method

End Type

Type TVoidObjPtr Extends TFPtr

Field _Ptr(Obj:Object)

'Constructors & Destructor
Method New()
Self._sType=TFPtr.C_sType_VoidObj
End Method

'Interfacing
Method Execute(Obj:Object)
Self._Ptr(Obj)
End Method

End Type

Type TObjVoidPtr Extends TFPtr

Field _Ptr:Object()

'Constructors & Destructor
Method New()
Self._sType=TFPtr.C_sType_ObjVoid
End Method

'Interfacing
Method Execute:Object()
Return Self._Ptr()
End Method

End Type

Type TObjObjPtr Extends TFPtr

Field _Ptr:Object(Obj:Object)

'Constructors & Destructor
Method New()
Self._sType=TFPtr.C_sType_ObjObj
End Method

'Interfacing
Method Execute:Object(Obj:Object)
Return Self._Ptr(Obj)
End Method

End Type

Type TVoid2ObjPtr Extends TFPtr

Field _Ptr(Obj:Object,Obj2:Object)

'Constructors & Destructor
Method New()
Self._sType=TFPtr.C_sType_Void2Obj
End Method

'Interfacing
Method Execute(Obj:Object,Obj2:Object)
Self._Ptr(Obj,Obj2)
End Method

End Type
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)

Bob

BeitragSo, Apr 10, 2011 22:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich danke euch für die Denkanstösse.

@ToeB
Das sieht gut aus.
So in etwa hab ich es mir vorgestellt.
Super schik wäre noch wen man den Name der Function als String übergeben könnte.

Also Anstelle von
Code: [AUSKLAPPEN]
Local Test1:TFunc = TFunc.Create( func1 )

so
Code: [AUSKLAPPEN]

Local myVar:string ="Click_Button(1)"
Local Test1:TFunc = TFunc.Create( myVar )

So könnte man schon mal alle nötigen Functionsaufrufe während der Laufzeit erzeugen.
Code: [AUSKLAPPEN]

Function Click_Button(BT:int)
    Print  "Click_Button " + BT
End Function


Anschliesend könnten dann diese Functionsgerüste
in eine Datei geschrieben weden. ich denke da z.B. an einen Gui Editor.
Er soll an den Spielen teilnehmen bis er spielend stirbt. MCP - TRON
 

n-Halbleiter

BeitragSo, Apr 10, 2011 22:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Das ginge (wenn auch eingeschränkt) über Reflection. Damit kannst du über die Namen von Objekten auf Types, Methoden und Felder zugreifen. Die Standardvariante unterstützt keine Funktionen, allerdings gibt's im englischen Forum eine Modifikation (Pointer und Funktionen werden dann unterstützt), mit der das geht. Einfach mal suchen. Zur Benutzung von BRL.Reflection kannst du in die Dokumentation schauen, mit der kann man das gut lernen.

Der einzige Nachteil von Reflection ist, dass du alles in Types packen musst, da für die anderen Funktionen im Releasemodus keine Metainformationen gespeichert werden (die man bräuchte, damit Reflection funktioniert). Und Features, die nur im Debugmodus arbeiten, braucht keiner. Wink
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)

Bob

BeitragSo, Apr 10, 2011 23:48
Antworten mit Zitat
Benutzer-Profile anzeigen
@ n-Halbleiter
Danke für den Hinweis.
Bin tatsächlich überrascht das dies, wen auch eingeschränkt, möglich ist.
Ich denke ich werd es dennoch nicht versuchen wen es keine einfacherer Möglichkeit gibt. Ansonsten müsste ich mich, mal wieder, noch tiefer in den ganzen Sumpf wagen.

Ich bin eigentlich noch dabei ToeB's Beispiel zu verdauen.
Ist zwar Grundsätzlich, in der Form wie gepostet, nicht schwer aber ich bekomme es nicht hin Functionen in die Liste einzutragen die einen Paramter haben. Embarassed

Code: [AUSKLAPPEN]
Local Test1:TFunc = TFunc.Create( func1(was_auch_immer:int ))


Ich denk das man dann auch an der Function Create des Type tFunc
was ändern muss, wahrscheinlich auch beim finale aufrufen der Function aus der List, aber wie das geht ist mir noch ein rätsel.
Alle versuche meinerseits führen zu Konvertierungsproblemen.

@ToeB
Wen du noch mal ne ruhige Minute hast, würd ich mich über einen Tipp freuen.

Ich denke man könnte es auch so hin bekommen das man belibig viele Parameter in z.B. einen Type paken könnte dessen einziges Feld eine Liste ist. So wären alle Functionen von der gleichen Beschaffenheit.
Nämlich alle mit exakt einem Parameter der auch noch immer vom selben Typ ist.
Er soll an den Spielen teilnehmen bis er spielend stirbt. MCP - TRON
 

n-Halbleiter

BeitragMo, Apr 11, 2011 0:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Das Problem liegt daran, was ToeBs Beispiel für einen Funktionspointer verwendet (FuncPtr:Object()). Blitzmax funktioniert bei einer solchen Deklaration NUR mit Funktionen, die ein Objekt zurückgeben (":Object") und keine Parameter haben ("()").

Allerdings ist mir gerade wieder eine Möglichkeit in den Sinn gekommen, wie du das doch hinkriegen könntest: Deklariere deinen Pointer intern als Byte Ptr und caste dann zu dem Funktionspointer, den du brauchst. Dazu ein Beispiel. BlitzMax: [AUSKLAPPEN]
SuperStrict

Local pPtr:Byte Ptr'Hält alle Typen von Funktionen

pPtr=Fnc1

Local FPtr1:Object(i:Int)=pPtr'Vor dem Aufruf muss gecastet werden
FPtr1(2)

pPtr=Fnc2

Local FPtr2(r:Float,p:Byte Ptr)=pPtr
FPtr2(3,Null)

Function Fnc1:Object(i:Int)
Print "Fnc1: Object(Int)"
End Function
Function Fnc2(r:Float,p:Byte Ptr)
Print "Fnc2: (Float,Byte Ptr)"
End Function


Das Casten erfolgt implizit, indem du einfach deiner Pointervariable den aktuellen Byte Ptr zuweist.
Noch ein paar Hinweise:
Arrow Du kannst überprüfen, ob ein Function Pointer auf keine Funktion zeigt, indem du ihn auf <>Null prüfst.
Arrow Passe höllisch auf, dass du richtig castest, denn das übernimmt BlitzMax nicht, wenn du Funktionspointer als Byte Ptr speicherst. Dazu folgendes Beispiel, das eine EAV auswirft (das obige Beispiel, nur leicht modifiziert.) BlitzMax: [AUSKLAPPEN]
SuperStrict

Local pPtr:Byte Ptr'Hält alle Typen von Funktionen

pPtr=Fnc1

Local FPtr1:Object(i:Int)=pPtr'Vor dem Aufruf muss gecastet werden
FPtr1(2)

pPtr=Fnc2

'Anstatt einen korrekten Funktionspointer zu erstellen und zuzuweisen, weisen wir dem alten Pointer eine Funktion zu, die andere Parameter und einen anderen Rückgabewert besitzt. BlitzMax beschwert sich nicht. Aufrufen können wir die Funktion auch, allerdings wird es dann mit den Parametern lustig (in diesem Beispiel beschwert sich BM darüber, dass der Byte Ptr auf 'Null' verweist und damit nicht anzeigbar ist. Kommentieren wir in der betreffenden Zeile alles nach dem ersten Plus (einschließlich) aus, dann ergibt das auch einen lustigen Wert.) Wie gesagt, man muss aufpassen, BM frisst die Zuweisung und den Aufruf, allerdings werden die Parameterwerte anders, da sich die Variablentypen unterscheiden.
FPtr1=pPtr
FPtr1(1)

Function Fnc1:Object(i:Int)
Print "Fnc1: Object(Int)"
End Function
Function Fnc2(r:Float,p:Byte Ptr)
Print "Fnc2: (Float,Byte Ptr)"
Print r+";"+p[0]
End Function


Ich hoffe, das ist soweit verständlich. Viel Spaß. ^^'
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group