C++ Code zur Laufzeit dynamisch zusammenstellen

Gast #6330372
Lesenswert?

Hallo,

ich möchte ein C++ Programm versuchen zu schreiben wo Bedingungen aus 
verschiedenen vorgefertigten Modulen (Funktionen, Operatoren(> < && ||)) 
per Zufall zusammengestellt werden und dann ausgeführt werden.

Als grobes Beispiel es gibt 100 Funktionen mit Rückgabewerten (genannt 
FR) und es gibt Operatoren wie < > && || und es gibt weitere 100 
Funktionen mit bestimmten Aktionen (genannt FA). Nun soll random daraus 
eine Kombination erstellt werden können wie zB:

if(FR1() > FR2() && FR4 < FR8 && FR1 < FR9)
{
   FA3();
}

Meine Frage wäre wie würde man das grundsätzlich angehen von der 
Datenstruktur? In welcher Datenstruktur erzeugt man so eine 
Aneinanderreihung von Funktionen und Operatoren die miteinander zur 
Laufzeit dynamisch kombiniert ausgeführt werden sollen? Und wie setzt 
man das um damit auch das Programm performant bleibt?

Ein Ansatz wäre sicherlich auf Stringbasis die Code-Module nach 
funktionierenden Regeln zusammenstellen zu lassen und dann zur Laufzeit 
zu Libs zu kompilieren und einzubinden (zb dlopen()). Etwa wie in dieser 
Ansatz: 
https://stackoverflow.com/questions/11016078/is-it-possible-to-create-a-function-dynamically-during-runtime-in-c/11016382#11016382

Meine Frage wäre, geht so etwas auch ohne besondere Perfomance-Verluste 
direkt in C++ mit Hilfe irgendwelcher dynamisch erstellten 
Datenstrukturen welche dann den entsprechenden Codeablauf von Funktionen 
und Operatoren abgearbeiten können? Wo packe ich sozusagen die 
Kombination solcher Module rein was als Ganzes dann natürlich noch 
ausführbar sein soll?

Grüße
#6330381
Lesenswert?

Was du suchst ist eine "embedded scripting language", sprich eine 
Skriptsprache die eingebunden und ausgeführt werden kann. Eine Liste 
solcher Sprachen gibt es etwa hier:

https://github.com/dbohdan/embedded-scripting-languages

Der prominenteste Vertreter ist wohl Lua, der vor allem in der 
Spieleindustrie sehr häufig zum Einsatz kommt. Zu Lua würde ich auch 
persönlich raten weil:
-) Der Core sehr klein ist. (~200kB)
-) Die Community groß und die Entwicklung im Gegensatz zu vielen anderen 
Vertretern auf der Liste aktiv ist.
-) Die C++ Bindings in Form von sol2 (https://github.com/ThePhD/sol2) so 
ziemlich das Beste sind was es gibt.

/edit
Deutsche Sprache...
Beitrag #6330400 wurde von einem Moderator gelöscht.
Gast #6330402
Lesenswert?

CPPDYN schrieb:
> if(FR1() > FR2() && FR4 < FR8 && FR1 < FR9)
> {
>    FA3();
> }

Bei dem Durcheiander voon Funktionsaufrufen und Variablen habe ich so 
meine Zweifel ...

> Meine Frage wäre wie würde man das grundsätzlich angehen von der
> Datenstruktur?

... aber schau dir mal
https://www.gnu.org/software/libmatheval/
an. Du baust einen String zusammen, der dann interpretiert wird.

leo
Gast #6330407
Lesenswert?

zitter_ned_aso schrieb:
> In einem Array aus Funktionszeigern alle 100 Funktionen ablegen und dann
> diese per Zufall aufrufen?
>
> Natürlich müssen dann diese Funktionen die gleiche Signatur haben.

interessanter Ansatz das wäre sogar ein performant, aber wie würde man 
dann das mit den Verknüpfungen der Funktionen per Operatoren machen? 
Muss ich nochmal überlegen...
Gast #6330448
Lesenswert?

CPPDYN schrieb:
> dann das mit den Verknüpfungen der Funktionen per Operatoren machen?

Genauso mit Zeigern?

Erst mal Funktionen erzeugen:
1
                                                                        
2
bool foo_and(int (fp1)(void), int (fp2)(void)){                         
3
   return fp1() && fp2();                                               
4
}                                                                       
5
                                                                        
6
bool foo_or(int (fp1)(void), int (fp2)(void)){                          
7
   return fp1() || fp2();                                               
8
}
9

10
usw.
Und dann auch diese in einem Array von Funktionszeigern unterbringen.

Aber wie kann es
CPPDYN schrieb:
> und es gibt weitere 100
> Funktionen mit bestimmten Aktionen (genannt FA).

100 Funktionen geben? Da steht doch eine if-Anweisung. Und diese hat nur 
zwei Zustände (true/false). Wie können diese 100 Fuktionen auf zwei 
Zustände verteilt werden? Auch per Zufall?
Gast #6330479
Lesenswert?

zitter_ned_aso schrieb:
> 100 Funktionen geben? Da steht doch eine if-Anweisung. Und diese hat nur
> zwei Zustände (true/false). Wie können diese 100 Fuktionen auf zwei
> Zustände verteilt werden? Auch per Zufall?

war natürlich erstmal nur ein Beispiel, aber ja im Grunde alles per 
Zufall, aus den 100 Funktionen mit Rückgabewert wird in Kombi mit 
zufälligen Operatoren eine Bedingung gemacht bei der auch wiederum 
zufällig sein kann wieviele Bedingungen aneinandergehängt werden (durch 
zB && ||). Wenn dann Bedingung erfüllt ist, dann soll eine der 
Aktionsfunktionen ausgeführt werden die auch wiederum zufällig gewählt 
ist...

Interessanter Ansatz mit den Funktionszeigern weil das auch schön 
low-level ist. Die Frage wäre auch ob man dann auch langfristig 
Verzweigungen (verschachtelte ifs... erzeugen könnte). Muss später mal 
ein paar Sachen testen... :-)
#6330485
Lesenswert?

CPPDYN schrieb:
> aber ja im Grunde alles per
> Zufall, aus den 100 Funktionen mit Rückgabewert wird in Kombi mit
> zufälligen Operatoren eine Bedingung gemacht bei der auch wiederum
> zufällig sein kann wieviele Bedingungen aneinandergehängt werden (durch
> zB && ||). Wenn dann Bedingung erfüllt ist, dann soll eine der
> Aktionsfunktionen ausgeführt werden die auch wiederum zufällig gewählt
> ist...

Klingt nach Kunst.
#6330488
Lesenswert?

CPPDYN schrieb:
> Dirk K. schrieb:
>> Kannst auch mal nach dem Command-Pattern
>> suchen, ein ähnliches Problem hab ich mal
>> damit gelöst.
>>
>> merciless
>
> Meinst du damit OOP also per virtuelle Funktionen etc etwas bauen?
Hier ein Beispiel (ziemlich Pseudocode):
Ich habe damit komplexe mathematische Formeln
flexibel in einer DB abgelegt und zur Laufzeit
die Formel mit Hilfe von einzelnen Commands
zusammengestöpselt. Jede Formel lag als
Baumstruktur in einer Tabelle abgelegt.
So konnte man durch Änderungen in der DB
die Berechnungsvorschrift ändern, ohne neu
kompilieren zu müssen. Hochperformant ist
das natürlich nicht, aber sehr flexibel.
1
// Calculator-Interface
2
class ICalculator
3
{
4
public:
5
  double Calc();
6
}
7

8
// Addition
9
class Add : public ICalculator
10
{
11
private:
12
  ICalculator * left;
13
  ICalculator * right;
14
  
15
public:  
16
  Add(ICalculator * left, ICalculator * right)
17
  {
18
    this->left = left;
19
    this->right = right;
20
  }
21

22
  virtual double Calc()
23
  {
24
    return left->Calc() + right->Calc();
25
  }
26
}
27

28
// Multiplikation
29
class Sub : public ICalculator
30
{
31
private:
32
  ICalculator * left;
33
  ICalculator * right;
34
  
35
public:  
36
  Sub(ICalculator * left, ICalculator * right)
37
  {
38
    this->left = left;
39
    this->right = right;
40
  }
41

42
  virtual double Calc()
43
  {
44
    return left->Calc() - right->Calc();
45
  }
46
}
47

48
// const Value
49
class Const : public ICalculator
50
{
51
private:
52
  double value
53
  ICalculator * right;
54
  
55
public:  
56
  Const(double value)
57
  {
58
    this->value = value;
59
  }
60

61
  virtual double Calc()
62
  {
63
    return value;
64
  }
65
}
66

67
// Anwendung (die magic numbers stammten natürlich 
68
aus Variablen, die zur Laufzeit geändert wurden)
69
// result = (4711-27) + 42;
70
ICalculator * calc = new Add(new Sub(new Const(4711), new Const(27)), new Const(42));
71
double result = calc->Calc();

merciless
Gast #6330525
Lesenswert?

Wenn es dir ums lösen von mathematischen Ausdrücken geht, kannst du z.B. 
auch GNU Octave einbinden und das die Auswertung erledingen lassen. Oder 
Python. Bei beiden kannst du dir die Implementierung anschauen, wie man 
einen Interpreter schreibt.
Gast #6330735
Lesenswert?

Es kommt sehr darauf an was du genau erreichen möchtest, einfache 
logische Operationen?, das komplette Typenspektrum von C++?, Funktionen 
mit n Parametern, Nur Ints oder auch Float, Strings? Was bedeutet für 
dich Performanz, genau so schnell wie kompiliert?

Wenn du dein Ziel so abstrakt laesst ist es schwierig dir konkrete Tips 
zu geben

Falls es nur einfache Operationen sind könntest du damit den Code 
dynamisch erzeugen, mit relativ gleicher Performanz
https://asmjit.com
Gast #6330805
Lesenswert?

Das geht prinzipiell auch per Textfresser: 2 Coderümpfe erstellen, und 
den random-Code dazwischenschieben, compilieren, ausführen.

Aber ich fürchte, ich weiss nicht, wozu, also kann ich auch nicht ahnen, 
worauf es Dir ankommt.
Gast #6331589
Lesenswert?

Das haben einige sehr erfolgreich bereits umgesetzt, ist lange her.
Herausgekommen sind dabei so Sachen wie Python , Java , Perl , 
Lua ...

Nur zu: richtig gute C++ Programmierer welche das Rad nochmals erfinden 
sind immer gefragt!
#6331928
Lesenswert?

Nimm einen std::vector auf std::function<> und shuffle() den, dann 
schreib für die Operatoren irgendwas, was zwei Argumente nimmt und einen 
zufälligen Operator drauf anwendet. Wenn das was du beschreibst 
tatsächlich alles ist was du machen willst, gibt es wirklich einen 
Haufen einfache Lösungen für das Problem.
Gast #6332839
Lesenswert?

mh schrieb:
> Programmiersprachentheaterintendant schrieb:
>> Das haben einige sehr erfolgreich bereits umgesetzt, ist lange her.
>> Herausgekommen sind dabei so Sachen wie [...] , Perl ,
>> [...] ...
>
> Ich habe es gewusst, Perl ist eine rein zufällige Kombination von
> Operatoren und Funktionen!

Natürlich stimmt das so, auch wenn Du nur die Syntax meinst :-) (ich 
auch!)

Die Zufälligkeit ist aber auch ganz bestimmt der 
interessante/schwierige Teil an der Fragestellung des TOs...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren