Command Handler
-
Tim06TR schrieb:
typedef unsigned int Adress; //--------------------------------------------------------------------------- //Ein Zeiger auf einen beliebigen Typen mit Typnamen: struct DynTypePointer { Adress Adresse; char* Typ; DynTypePointer(Adress Adresse, const char* Typ) { this->Adresse = Adresse; strcpy(this->Typ,const_cast <char*> (Typ)); } }; //---------------------------------------------------------------------------
Wenn Du sowas vor hast, warum nicht type_info benutzen?
Tim06TR schrieb:
Oder die folgende Idee zu einem Smart Pointer Konstrukt, dass seine Kopien kennt und sich erst löscht, wenn alle Klone tot sind:
Ok, das sieht man gelegentlich. Meistens, weil Leute traurig sind, daß C++ doch anders ist als Java. Es kann aber auch sinnvoll sein.
Die Smart-Pointers können refcounting betreiben oder sich in einer Liste gegenseitig kennen. Der letzte macht das List aus.
Und Du hast Dich mal für die Liste entschieden. Ok. Die hat Vor- und Nachteile (und wird meistens unterschätzt). Ich hoffe, ich habe das so recht verstanden. Weil Du von Eltern und Erben erzählst statt von gleichberechtigten Nachbarn.
Falls es die Nachbarversion sein soll: Smart-Sachen und Listen-Sachen sind zwei Klassen. Wiedermal eine intrusive Liste.Da sie niemals leer ist, können wir uns einen doppelt verketteten niemals leeren Ring gönnen, dann fliegen die ganzen Vergleiche gegen 0 heraus. Und der op[], das Holen des ersten oder letzten Elements gehören gar nicht rein.
-
knivil schrieb:
TyRoXx schrieb:
Das macht man in Java, weil es da keine Funktionszeiger bzw. so etwas wie Delegates aus C# gibt. Es gibt keinen Grund, das in C++ so zu machen.
Bullshit! Auf Boost verzichte ich gern. Funktion(szeiger) haben eine Feste Parameteranzahl und koennen keinen Kontext speichern. Ich habe hier sowas wie "poor mans closure".
Mit Betonung auf poor. Warum soll dein low-level-Ansatz besser sein als
function
plusbind
?
-
TyRoXx schrieb:
Mit Betonung auf poor. Warum soll dein low-level-Ansatz besser sein als
function
plusbind
?1.) Leg mir keine Worte in den Mund.
2.) Er ist simpel.
-
knivil schrieb:
2.) Er ist simpel.
Hat aber gegenüber std::function, std::bind gewisse Einschränkungen die ich durchaus berücksichtigen würde. Entgegen eines Funktionszeigers kann std::bind eben auch:
a) Memberfunktionen/Methoden aufrufen.
b) Man kann Argumente fest binden, sofern nötig.
c) Man kann Funktionssignaturen in bestimmten Grenzen anpassen (z.B. Reihenfolgen) ohne den Code an mehreren Stellen ändern zu müssen.Teure Smartpointer (wie shared_ptr) würde ich aber auch nur einführen, wenn im Szenario unbedingt nötig, und nicht früher...
-
Autsch @ mein uraltes DynTypeHandle Konstrukt.
Ich hätte nochmal drüberschauen sollen.Ich hab das nochmal etwas abgeändert.
//--------------------------------------------------------------------------- typedef void* Handle; // Does not handle the ressource at all! struct DynType { Handle Instance; std::type_info* InstanceType; ~DynType() { delete InstanceType; } }; //--------------------------------------------------------------------------- template <class T> DynType CreateDynType(T* Object) { DynType Dyn; Dyn.Instance = static_cast <Handle> (Object); Dyn.InstanceType = new std::type_info(T); return Dyn; } //--------------------------------------------------------------------------- template <class T> T GetDynType(const DynType& Dyn) { if (*Dyn.InstanceType == typeid(T)) return static_cast <T*> (Dyn.Instance); else return static_cast <T*> (0); } //---------------------------------------------------------------------------
Sowas wie ein Variant wäre echt mal nett.
Ich weiß, dass das oben immer noch nicht sehr schön ist, aber füttert mich mal mit ein bisschen Alternativen.Die Parameter der Prozeduren sind ja nicht immer gleich, noch sind es gleich viele. Auf Parameter verzichten ist nicht möglich.
-
Sag uns doch mal in Worten was du wirklich machen willst, für mich sieht dies alles eher sehr unausgegoren und unverständlich aus.
-
Ok nochmal:
1. Command Handler (Console / Server)
2. Ein große Liste mit Befehlen und den dazugehörigen Prozeduren
a. Die Prozeduren haben n Parameter
b. Die Parameter davon haben differente Typen- Die Befehle sind zur Steuerung des gesammten Programms, brauchen deshalb auch unterschiedliche "Bekanntschaften". Ich will kein Gottobjekt, wenn möglich.
Mögliche weitere Dinge wären:
- Eine Warteschlange für hereinkommende Befehle. Der Listener in einem Thread, der die Befehle auffängt und zur Liste hinzufügt.Das ist eigentlich alles kein Problem, könnte loslegen, wenn ich wollte. Aber ob ich hinterher noch alles durchblicken kann ist ne andere Frage & ob ich nach dem 100000ten Befehl nicht eine Sekunde warten muss, bis der den überhaupt gefunden hat.
Zudem will ich keine Kapselung aufgeben oder, anders ausgedrückt, einen imperativen Code basteln. Basteln trifft es bei unüberlegtem Programmdesign sowieso immer ganz gut.
-
Tim06TR schrieb:
Ok nochmal:
Nein nicht nochmal, wir wollen eine Erklärung von dem was du dir vorstellst, und dem Sinn dahinter. Mit wenigen Stichworten können wir nur raten.
Beginnen wir einfach mal:
Tim06TR schrieb:
Command Handler (Console / Server)
Command Handler ist vermutlich weniger das Verständnisproblem (Außer vielleicht wenn man deinen Code dazu nimmt), recht schwammig ist dabei aber das was du im Zusammenhand mit Console/Server darein interpretieren magst.
Tim06TR schrieb:
2. Ein große Liste mit Befehlen und den dazugehörigen Prozeduren
a. Die Prozeduren haben n Parameter
b. Die Parameter davon haben differente Typen2 an sich ist noch okay, aber wie stellst du dir a&b vor, und mit welchen Sinn, und vor allem: Wann stehen die Parameter genau fest? Eine Befehlsliste macht imho wenig Sinn wenn man dann noch raten muss wie man die Parameter füllt. C++ ist keine dynamische Sprache.
Ungeachtet davon was ich davon halten würde wäre eine Variante natürlich die Signatur deiner Befehle immer in String-Wertepaaren anzugeben (natürlich fehlt jegliche Typprüfung etc.). z.b.:
std::map<string, string> <funktion>(std::map<string, string> parameter);
Aber wie gesagt, der Sinn wäre eher fraglich.
Wenn ich eine Liste von Befehlen halte, würde ich erwarten das die beim Aufruf ihre Sachen machen, ohne irgendwelche Parameter. Die Befehle wiederum haben aber natürlich wieder selbst die Möglichkeit sich bestimmte Informationen aus dem System zu holen (Auch wenn Singletons nicht gerne gesehen werden: z.B. aus einer Konfigurationsklasse).
Wenn wiederum die Parameter beim Aufruf festgelegt werden können, oder zumindest gesagt werden kann, mit welcher Funktion beim Aufruf die Informationen geholt werden können, sind wir wieder bei std::function und std::bind.
Beispiel (ungetestet, und grad bei den verschachtelten unsicher):
class A { void foo1(int a) {}; void foo2(int b, int c) {}; static void foo3() {}; }; void foo4() {} void foo5(int a) {} int getFoo6() { return 1 }; int main() { A a; std::map<string, std::function<void (void)>> befehlsliste; befehlsliste["foo1"] = std::bind(&A::foo1, &a, 4); befehlsliste["foo2"] = std::bind(&A::foo2, &a, 2, boost::bind(&getFoo6)); befehlsliste["foo3"] = std::bind(&A::foo3); befehlsliste["foo4"] = std::bind(&A::foo4); befehlsliste["foo5"] = std::bind(&A::foo5, boost::bind(&getFoo6)); // Aufruf: befehlsliste["foo3"](); }
-
asc schrieb:
Wenn ich eine Liste von Befehlen halte, würde ich erwarten das die beim Aufruf ihre Sachen machen, ohne irgendwelche Parameter.
Also Aufträge (Jobs)(die sicher ihre Parameter kennen), und Befehle (Commands)(die z.B. in Basic Parameter brauchen).
Ich denke, es sollen Jobs über das Netz oder nur über die Zeit verschickt werden.
-
Meine Codeschnipsel waren nicht mit dem Problem an sich verbunden, da wollte ich noch hinkommen -.-.
&Mir ist gerade eingefallen, dass die Parameter ohnehin nur Strings sind.. vor allem weiß der Aufrufer doch gar nicht die Parametertypen...
-
Hier sagst Du irgendwas...
knivil schrieb:
...Bullshit! Auf Boost verzichte ich gern. Funktion(szeiger) haben eine Feste Parameteranzahl und koennen keinen Kontext speichern. Ich habe hier sowas wie "poor mans closure".
Und hier revidierst Du Dich selbst und gibst als Alternative Lösung etwas funktinal äquivalentes und technische schlechteres, selbstgefrickeltes an:
knivil schrieb:
Oder der Java-Ansatz
struct Command { virtual void execute() = 0; virtual ~Command() {} }; std::map<std::string, Command*> commands;
Von dieser kann abgeleitet werden und durch Membervariablen fuer Parameter, Kontext etc. erweitert werden....
Also was denn nun?
-
Das Bullshit bezog sich auf: Es gibt keinen Grund, das in C++ so zu machen. Als ob das jemals jemanden von irgendwas abgehalten haette. Aber da weder Umfang, Bezug zur Anwendung oder Anforderungen genannt werden, waehle ich das aus meiner Sicht einfachste.
funktinal äquivalentes und technische schlechteres, selbstgefrickeltes
Das ist ein einfaches Interface mit 3 Zeilen Code. So viele (negative) Eigenschaften kann es gar nicht besitzen.
-
Das Interface selbst ist ja nicht böse, die Verwendung ist halt umständlich.
Wobei man natürlich ganz einfach ein Funktions-Template basteln könnte, das dann beliebige Funktoren in das Interface einwickelt.Je mehr man allerdings in diese Richtung geht, desto ähnlicher wird es zu std::function.
Und irgendwann sollte man sich dann fragen: wieso nicht gleich std::function nehmen.
Wobei ich deinen Standpunkt durchaus verstehe. Speziell im Interface von Libs kann es sinn machen selbst zu backen, Standard halt nur Standard ist, aber nicht heisst dass es überall vorhanden ist oder gar gleich funktionieren würde.