std::function in file schreiben?
-
Hallo,
ich habe eine Frage, und zwar habe ich momentan eine Klasse welche ein physikalisches System darstellt. Dieses System ist ziemlich frei konfigurierbar was Parameter etc angeht. Allerdings kann man auch diverse interne Funktionn konfigurieren, also etwa so (nur ein Minimalbeispiel):
class physical_system { public: physical_system(); double output(double input) { return output_function(input); } void set_output_function(std::function<double(double input)> const &new_output_function) { output_function = new_output_function; } private: std::function<double(double input)> output_function; };Allerdings will ich jetzt eine fertig konfigurierte Instanz von
physical_systemin eine Textdatei schreiben können, so dass ich sie zu einem späteren Zeitpunkt wieder laden kann.Mit Parametern ist das ja kein Problem, da schreibe ich einfach deren numerischen Wert in die Textdatei. Aber wie speichere ich das std::function Objekt, welches der Benutzer übergibt, in einer Textdatei so dass ich dieses nach dem Laden wieder benutzen kann?
Geht das überhaupt?
-
Mit Java.
-
Nein, das geht im Allgemeinen nicht. Wie willst du eine Funktion serialisieren, die irgendwas tun kann und beliebig grossen Zustand im Rücken hat?
Du musst dich auf ein serialisierbares Format beschränken. Z.B. Strings, die du parst. Oder Blöcke primitiver Funktionen, die du zusammensetzt.
-
Der einfachere Weg wäre, dir eine map anzulegen, die Namen auf Funktionsaddressen mappt. Beim Speichern speicherst du einfach den Namen in die Datei und der kann dann beim Laden gelesen werden. Das Initialisieren der Map machst du hardcoded in irgendeiner Funktion.
-
Nathan schrieb:
Das Initialisieren der Map machst du hardcoded in irgendeiner Funktion.
Das Problem ist folgendes: Wären es alles Funktionszeiger, hätte er nicht
std::functionals Membertyp gewählt. Also dürften es auch Funktoren geben. Und die haben, wie Nexus bereits erwähnt hat, einen Zustand, und den müsste man ebenfalls Serialisieren - nur kann man nicht auf das Objekt zugreifen, dass function hält.
Was also wird an
set_output_functionübergeben?
-
Wenn du so etwas machen möchtest, ist
functiondie falsche Wahl. Du musst wohl selbst eine Schnittstelle für serialisierbare Funktionen so definieren, wie du sie brauchst.
-
Nexus schrieb:
Nein, das geht im Allgemeinen nicht. Wie willst du eine Funktion serialisieren, die irgendwas tun kann und beliebig grossen Zustand im Rücken hat?
Verdammt, das hatte ich befürchtet...
Das Problem das ich jetzt habe ist, dass ich nicht einfach nem Kollegen die Textdatei schicken kann und der lädt das physikalische System bei sich und verwendet es direkt (für Simulationen etc.), sondern dass er auch noch alle Funktionen korrekt setzen muss, tatsächlich hat das System nämlich nicht nur ein
std::functionObjekt sondern einen (nicht gerade kleinen)vectoraus den Funktionen die intern verwendet werden... Das wäre dann der Konfigurationshorror und sehr Fehleranfällig.Arcoth schrieb:
Was also wird an
set_output_functionübergeben?Ja, also prinzipiell alles was sich mit der Signatur der std::function callen lässt, also was ein double als Parameter nimmt und einen double Wert zurückgibt... Also auch Funktoren, ja.
TyRoXx schrieb:
Wenn du so etwas machen möchtest, ist
functiondie falsche Wahl. Du musst wohl selbst eine Schnittstelle für serialisierbare Funktionen so definieren, wie du sie brauchst.Aber wie könnte sowas aussehen? Wenn derjenige der das System erstellt zum Beispiel folgende Funktion übergeben will:
double my_output_function(double input) { return sin(input)*sin(input); }wie kann man sowas serialisieren?
-
happystudent schrieb:
wie kann man sowas serialisieren?
Wie gesagt, z.B. als String
f(x)=sin(x)*sin(x)wobei du einen Parser brauchst. Aber das ist wohl die benutzerfreundlichste Methode.
Alternativ serialisierst du direkt einen Syntaxbaum wie
f(x)= * multiply * sin * x * sin * xIn beiden Fällen musst du eine endliche Anzahl Funktionen zuvor definieren.
Was dir enorm Arbeit abnehmen könnte, wäre eine Skriptsprache wie Lua. Du würdest dann die Funktionen extern im Skript definieren und bräuchtest zu C++ nur eine Schnittstelle
double function(double), z.B. mittels LuaBridge.Willst du durch das Lesen von Dateien neue, zuvor unbekannte Funktionen ausführen können? Oder sollen lediglich bereits kompilierte Funktionen ausgewählt werden? Im zweiten Fall würde eine Map Label->Function wie von Nathan vorgeschlagen tatsächlich helfen.
-
Nexus schrieb:
happystudent schrieb:
wie kann man sowas serialisieren?
Wie gesagt, z.B. als String
f(x)=sin(x)*sin(x)wobei du einen Parser brauchst.
Hm, das werde ich so nicht machen können, da Performance sehr wichtig bei der Anwendung ist (die Funktionen werden etliche male aufgerufen) was jetzt schon an der Grenze zur Echtzeitsfähigkeit ist, wenn ich da bei jedem call erstmal parsen muss wird das glaub ich nix...
Nexus schrieb:
Willst du durch das Lesen von Dateien neue, zuvor unbekannte Funktionen ausführen können? Oder sollen lediglich bereits kompilierte Funktionen ausgewählt werden? Im zweiten Fall würde eine Map Label->Function wie von Nathan vorgeschlagen tatsächlich helfen.
Also am liebsten wären mir auch unbekannte Funktionen, aber das wird denke ich zu aufwendig, daher werde ich wohl die Methode mit der map nehmen.
Danke auf jeden Fall für die Vorschläge

-
happystudent schrieb:
Nexus schrieb:
happystudent schrieb:
wie kann man sowas serialisieren?
Wie gesagt, z.B. als String
f(x)=sin(x)*sin(x)wobei du einen Parser brauchst.
Hm, das werde ich so nicht machen können, da Performance sehr wichtig bei der Anwendung ist (die Funktionen werden etliche male aufgerufen) was jetzt schon an der Grenze zur Echtzeitsfähigkeit ist, wenn ich da bei jedem call erstmal parsen muss wird das glaub ich nix...
Das bedeutet im Umkehrschluss, du liest im Moment aus eienr Datei ein und willst es sofort ausführen?!
Das bisschen Parsen macht die Performance dann nicht mehr schelchter neben der Dateioperation.
Aber was du wahrscheinlich eher machst, ist die Datei einlesen, alles speichern wie du es brauchst und dann damit arbeiten. Das Laden ist gewöhnlich nicht wirklich zeitkritisch, da kannst du auch so etwas parsen.
-
happystudent schrieb:
wenn ich da bei jedem call erstmal parsen muss wird das glaub ich nix...
Natürlich nicht bei jedem Aufruf, das Parsen machst du genau einmal beim Laden. Dann speicherst du die Funktion in einer effizienteren Datenstruktur.
-
Nexus schrieb:
Dann speicherst du die Funktion in einer effizienteren Datenstruktur.
// Funktion // | // v std::vector<std::string> functions; // ^ ^ // | | // effiziente Datenstruktur | // | // speichern
-
@happystudent
Könntest du vielleicht, statt aus einem Datenfile direkt ein "Physical System" im Speicher zu bauen, aus dem Datenfile C++ Code (*) generieren, diesen kompilieren, und dann ausführen?
Wenn's nicht stört dass es ein eigener Prozess ist, ist das ja denkbar einfach. Und wenn das stört gibt's immer noch die Möglichkeit ne .DLL bzw .SO zu verwenden.Oder du begibst dich auf die Suche nach einer Library mit der man solche Funktionen JIT kompilieren kann.
*: Bzw. muss es natürlich nicht C++ sein. Ich sag nur C++ weil ich annehme dass du vielleicht keine Lust hast den ganzen restlichen Code des "Physical System" in einer anderen Sprache nochmal neu zu implementieren.
-
Nimm einfach Lua + LuaJit.
LuaJit ist so effizient dass es Lua-Code relativ nah an die Performance von C annähert.
http://luajit.org/performance_x86.htmlDa schreibst du die Funktionen als Lua-Code in eine Textdatei die du zur Laufzeit lädst.
-
illustriert schrieb:
// Funktion // | // v std::vector<std::string> functions; // ^ ^ // | | // effiziente Datenstruktur | // | // speichernVersteh ich nicht, sorry. Über einen string muss ich ja immernoch drüber iterieren. Wenn ich jetzt etwas wie
"sin(x)*sin(x)"in meinem funktions-vector habe muss ich ja trotzdem bei jedem function-call über den string laufen. Das ist ja auf jeden Fall zig mal teurer als einfach nursin(x)*sin(x)auszurechnen...hustbaer schrieb:
@happystudent
Könntest du vielleicht, statt aus einem Datenfile direkt ein "Physical System" im Speicher zu bauen, aus dem Datenfile C++ Code (*) generieren, diesen kompilieren, und dann ausführen?
Wenn's nicht stört dass es ein eigener Prozess ist, ist das ja denkbar einfach. Und wenn das stört gibt's immer noch die Möglichkeit ne .DLL bzw .SO zu verwenden.Oder du begibst dich auf die Suche nach einer Library mit der man solche Funktionen JIT kompilieren kann.
Das wär natürlich cool... hab sowas zwar noch nie gemacht, aber werd mal danach googlen.
Ethon schrieb:
Nimm einfach Lua + LuaJit.
LuaJit ist so effizient dass es Lua-Code relativ nah an die Performance von C annähert.
http://luajit.org/performance_x86.htmlDa schreibst du die Funktionen als Lua-Code in eine Textdatei die du zur Laufzeit lädst.
Hm, ich seh da aber keinen Vergleich zu C, sondern nur zu verschiedenen Lua VMs... Diese Funktionsaufrufe sind Performancetechnisch der Begrenzende Faktor des Ganzen Systems, daher will ich durch die Serialisierung eigentlich gar keine Performance verlieren müssen...
-
happystudent schrieb:
Versteh ich nicht, sorry
War wohl auch nicht allzu ernst gemeint.
Was ich mit Datenstruktur meinte, war eher ein Syntaxbaum oder eine effizientere, auf spezifische Funktionen optimierte Variante davon. Aber an die Performance eines kompilierten oder JIT-interpretieren Programmes wirst du damit nicht herankommen.
Ein C++-Programm automatisch zu kompilieren dürfte nicht allzu schwer sein; die Zielmaschine muss halt einen Compiler installiert haben (ausser du willst den auch noch mitliefern). Du kannst vorgeben, dass gewisse Funktionen in der einzulesenden .cpp-Datei vorhanden sein müssen. Entweder du kompilierst sie direkt mit dem Rest deines Programms, oder machst eine Art Plugin-System wie von hustbaer erwähnt: Du spezifizierst eine Schnittstelle in einer dynamischen Bibliothek (.dll, .so), welche vom Hauptprojekt aufgerufen werden kann.
-
Ok, alles klar dann werd ich mich dies bezüglich mal informieren wie das geht. Dass ein Compiler Vorhanden sein muss macht nichts, das ist auf jeden Fall gegeben.
Viele Grüße,
hs
-
happystudent schrieb:
Hm, ich seh da aber keinen Vergleich zu C, sondern nur zu verschiedenen Lua VMs... Diese Funktionsaufrufe sind Performancetechnisch der Begrenzende Faktor des Ganzen Systems, daher will ich durch die Serialisierung eigentlich gar keine Performance verlieren müssen...
Weil du keine Funktionen serialisieren kannst.
Die einzige Möglichkeit wäre ein JIT-Compiler, dh. dein Programm schleppt einen kompletten C++-Compiler mit der die Möglichkeit bietet seinen Code direkt in den Speicher zu spucken. Clang kann das meines Wissens nach als einziger da die LLVM Support für JIT-Kompilierung hat.
Das ist aber sowas von krass übertrieben.
-
happystudent schrieb:
Ok, alles klar dann werd ich mich dies bezüglich mal informieren wie das geht. Dass ein Compiler Vorhanden sein muss macht nichts, das ist auf jeden Fall gegeben.
Warum schreibt der Kollege den Kram dann nicht direkt selbst in C++? Wozu der Umweg über irgendwelche "Serialisierung"?
-
TyRoXx schrieb:
Warum schreibt der Kollege den Kram dann nicht direkt selbst in C++? Wozu der Umweg über irgendwelche "Serialisierung"?
So wie ich happystudent verstanden habe, will er möglichst einfach diese Funktionen verschicken können, und idealerweise auch möglichst automatisch (d.h. der Kollege muss nicht jedes Mal manuell kompilieren).