Funktion "erstellen"



  • Hallo.

    Ich weiss leider nicht wie man es nennen soll und so suche ich nun schon seit Stunden in google nach einer passenden Beschreibung/Hilfe.

    ExprFunc1V = function(const x: Extended): Extended;
    
    SinC   : ExprFunc1V;
    
    SinC := CompileExpr(ParseExpr('sin(x)/x',['x']),tyPass1V);    // parse and compile expression
    Result := SinC(1.0);                                          // evaluate the Expression
    FreeFunc(@SinC);                                              // Free Function
    ShowMessage('Result = '+FloatToStr(Result));
    

    Ich möchte diesen Delphi Code gerne in C++ übernehmen, jedoch weiss ich nicht wie man so wie dort eine Funktion "erstellt".

    Der erste Schritt wäre

    typedef Extended __fastcall (*ExprFunc1V)(const Extended x);
    

    und
    ExprFunc1V SinC;

    Aber wie caste(?) ich jetzt die Ausgabe von CompileExpr() in eine Funktion

    ExprFunc1V SinC = (ExprFunc1V*)CompileExpr(ParseExpr("sin(x)/x", v, ARRAYSIZE(v)-1),tyPass1V); // Das bringts leider nicht  :rolling_eyes:
    

    und gebe diese auch wieder frei?

    Bitte einer muss das doch wissen, wenigstens nach welchem Begriff man suchen muss um irgendwie ansatzen zu können 😞



  • Is das ein Funktionszeiger?



  • Ach oben die Zeile war nicht richtig

    ExprFunc1V SinC = (ExprFunc1V)CompileExpr(ParseExpr("sin(x)/x", v, ARRAYSIZE(v)-1),tyPass1V); // ohne den Stern
    

    Der Fehler daran ist aber das beim Start ein Speicherfehler Error kommt.

    CompileExpr() ist **void ***

    extern PACKAGE void * __fastcall CompileExpr(const Expression &Bytecode, tyPassType PT);
    

    Ich habe auch schon probiert

    ExprFunc1V SinC = 0;
    SinC = (ExprFunc1V)CompileExpr(ParseExpr("sin(x)/x", v, ARRAYSIZE(v)-1),tyPass1V); // ohne den Stern
    

    Oft hilft es ja 0 zu setzen, leider hier nicht 🙂

    Es compiliert, aber Speichererror bei Ausführung. Eine Ahnung woran es hängt?



  • midori schrieb:

    Oft hilft es ja 0 zu setzen

    Kann schon sein, aber nicht in C++.

    Gibt denn CompileExpr() eine gültige Adresse zurück?
    Und ob die Funktionssignatur von ExprFunc1V richtig ist, ist auch noch so ein Thema. Normalerweise nutzt man in C++ keine const by-value Übergaben.



  • Nunja, in C(++) kann man nicht wirklich neue Funktionen zur Laufzeit definieren - du könntest höchstens den Zeiger auf eine bereits existierend Funktion zurückliefern. Aber da du beliebige Nutzereingaben in Funktionen verwandeln willst, dürfte das etwas problematisch werden (da du für jede potentiell mögliche Eingabe die passende Funktion brauchst), da wäre vermutlich eine Parser-Klasse sinnvoller, die den String zur Laufzeit durchgeht:

    class function_parser
    {
    public:
      function_parser(const std::string& the_func): m_func(the_func) {}
      operator()(double x, double y=0, double z=0)
      {
        // hier drin m_func auswerten und die Parameter einsetzen
      }
    private:
      std::string m_func;
    }
    

    (in dem Beispiel kann die berechnete Funktion bis zu drei Parameter haben)

    Zum Parsen der Eingabe empfehle ich z.B. Spirit (hab' recht gute Erfahrung damit gemacht) oder lexx.



  • @_midori_
    Wenn der Speicherfehler in der gezeigten Zeile kommt, dann ist es entweder die Funktion ParseExpr oder CompileExpr. Die Zuweisung des Ergebnis der Funktion CompileExpr (selbst wenn es eine ungültige Zahl ist) sollte erstmal keinen Fehler produzieren. Insofern ist es auch irrelevant, ob Du vorher die Variable auf 0 setzt. Wenn die zurückgebene Adresse ungültig ist (also kein Zeiger auf eine Funktion mit der gegebenen Signatur), bekommst Du einen Absturz, wenn Du versuchst, die Variable zu nutzen.

    @groovemaster
    Extended ist in Delphi/C++Builder ein 10 Byte Floating Point Wert und damit "praktisch" ein POD. siehe z.B
    http://www.merlyn.demon.co.uk/pas-type.htm
    Daher ist das f(const Extended x) vergleichbar mit f(const double d).



  • @CStoll
    Das Ding erzeugt tatsächlich eine neue Funktion. Siehe den Thread unter:
    http://www.delphi-forum.de/viewtopic.php?t=36946&postdays=0&postorder=asc&start=20
    Der geparste Ausdruck wird zur Laufzeit compiliert...



  • niemand schrieb:

    Extended ist in Delphi/C++Builder ein 10 Byte Floating Point Wert und damit "praktisch" ein POD.

    Viel inbteressanter ist allerdings, WIE der Parameter übergeben wird. const macht eigentlich nur bei by-reference 🙂 Sinn. Deshalb hab ich mich gefragt, ob die by-value Deklaration unter C++ überhaupt richtig ist.



  • Delphi entscheidet selbst ob const Parameter als Referenz übergeben werden oder nicht.

    Der Grund warum man Parameter als const und by-Value deklariert, ist zu dokumentieren, dass innerhalb der Funktion der Wert nicht geändert wird (für den Leser der Funktion, nicht für den Aufrufer). Bei hinreichend kurzen Funktionen wird das natürlich wieder überflüssig.


Anmelden zum Antworten