Hallo, ich habe da eine Problemstellung, bei der ich für ein paar Anregungen dankbar wäre. Ich habe mehrere eigenständige SW-Module, die dafür gedacht sind, sowohl von der Komandozeile, als auch mit einem GUI-Frontend aufgerufen zu werden. Als Schnittstelle dient dabei eine Funktion, der ich die Paramter (entweder die kopierten CL-Parameter, oder eben von der GUI zusammengestellt) als vector<string> übergebe. Jetzt hat zwar jedes Modul diese einheitlich definierte Schnittstelle, aber in der Regel unterschiedliche Parameter. Damit ich bei Hinzufügen/Ändern eines Moduls nicht jedes Mal die Aufrufumgebung anpassen muss, ist mein Plan, dass jedes Modul über eine weitere Funktion seine Parameter bekannt machen kann. Diese Funktion soll eine Liste mit Descriptor-Objekten der möglichen Parameter liefen. Ein solches Objekt z.B. folgende Informationen beinhalten: - CL-Bezeichnung (z.B. -f für einen Dateinamen) - Eine Kurzbeschreibung - Ggf. eine ausführliche Beschreibung - Den Typ (String, Int, Bool, ...) - Default-Werte - Für z.B. integer: Bereichs-Einschränkungen oder einzelne vorgegebene Werte - Eine Liste auswählbarer Werte, die z.B. in einer GUI in einem Pull-Down menü erscheinen) - Informationen welche Optionen sich gegenseitig ausschließen (Stichwort Radio-button). Dafür könnte man ja z.B. Objekte zu einer Gruppe zusammenfassen. - ... Ich suche jetzt nach eleganten Wegen eine solche Descriptor-Klasse aufzubauen. Eventuell wäre es auch sinnvoll für jeden Parameter-Typ eine eigene Klasse zu definieren und der gemeinsamen Basisklasse eine Funtion zu verpassen, mit der sich der Typ abfragen lässt (Ich denke da an sowas wie Qts QVariant). Für kreative Vorschläge bin ich dankbar und offen. Gruß
Wenns erstmal nur um "Variant" geht, evtl: http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html
Hallo Philip, Philip K. schrieb: > Ich habe mehrere eigenständige SW-Module, die dafür gedacht sind, sowohl > von der Komandozeile, als auch mit einem GUI-Frontend aufgerufen zu > werden. Als Schnittstelle dient dabei eine Funktion, der ich die > Paramter (entweder die kopierten CL-Parameter, oder eben von der GUI > zusammengestellt) als vector<string> übergebe. > > Jetzt hat zwar jedes Modul diese einheitlich definierte Schnittstelle, > aber in der Regel unterschiedliche Parameter. > Damit ich bei Hinzufügen/Ändern eines Moduls nicht jedes Mal die > Aufrufumgebung anpassen muss, ist mein Plan, dass jedes Modul über eine > weitere Funktion seine Parameter bekannt machen kann. > [...] > Für kreative Vorschläge bin ich dankbar und offen. Da gibt es auch Boost.Program_options oder auch sowas:
1 | // compile: LANG=C g++ -Wall -Wextra -ggdb -std=c++11 main.cpp
|
2 | |
3 | #include <iostream> |
4 | #include <string> |
5 | #include <vector> |
6 | #include <cstdlib> |
7 | |
8 | using namespace std; // pfui!1! |
9 | |
10 | |
11 | class ModuleBase { public: virtual void print(void) = 0; }; |
12 | class ModuleFactory {}; |
13 | |
14 | |
15 | class ModuleA: public ModuleBase { |
16 | private: int a; |
17 | public:
|
18 | ModuleA(int a): a(a) {} |
19 | void print(void) { cout << "ModuleA: " << a << endl; } |
20 | };
|
21 | class ModuleAFactory: public ModuleFactory { |
22 | public:
|
23 | static ModuleA* makeModule(vector<string> params) { |
24 | for(unsigned int e = 0; e < params.size(); ++e) { |
25 | if( params[e].compare( "-a" ) == 0 ) { |
26 | return new ModuleA( atoi(params[e+1].c_str()) ); |
27 | }
|
28 | }
|
29 | return NULL; |
30 | }
|
31 | };
|
32 | |
33 | |
34 | class ModuleB: public ModuleBase { |
35 | private: double b; |
36 | public:
|
37 | ModuleB(double b): b(b) {} |
38 | void print(void) { cout << "ModuleB: " << b << endl; } |
39 | };
|
40 | class ModuleBFactory: public ModuleFactory { |
41 | public:
|
42 | static ModuleB* makeModule(vector<string> params) { |
43 | for(unsigned int e = 0; e < params.size(); ++e) { |
44 | if( params[e].compare( "-b" ) == 0 ) { |
45 | return new ModuleB( atof(params[e+1].c_str()) ); |
46 | }
|
47 | }
|
48 | return NULL; |
49 | }
|
50 | };
|
51 | |
52 | |
53 | int main(int argc, char* argv[]) { |
54 | vector<string> vec; |
55 | vector<ModuleBase> modules; |
56 | for(int i = 0; i < argc; i++) { |
57 | vec.push_back( string(argv[i]) ); |
58 | }
|
59 | |
60 | ModuleA* a = (ModuleA*)ModuleAFactory::makeModule(vec); |
61 | ModuleB* b = (ModuleB*)ModuleBFactory::makeModule(vec); |
62 | if(a != NULL) { a->print(); } |
63 | if(b != NULL) { b->print(); } |
64 | }
|
Das ist jetzt auf die Schnelle gehackt und kann auch viel schöner gemacht werden. Natürlich kann man da statische help()-Methoden hinzufügen und die Module seriell in einen Array-Container packen, mit Templates arbyten oder ... Aber der eigentliche Trick ist, daß jedes Modul sich die für das Modul nötigen und nützlichen Parameter herauspickt und den Rest ignoriert. HTH, Karl
Hallo Karl, Boost sollte ich mir wohl insgesammt mal näher ansehen, da scheints viele nützliche Dinge zu geben. Zu Deinem Beispiel - Danke für die Mühe, aber das ist nicht ganz das was ich meinte. Ich versuchs nochmal anders: - Ein Programm (GUI, da wirds anschaulicher) wird mit einer erweiterbaren Anzahl von Modulen kompiliert. Diese Module haben eine einheitliche Aufrufschnittstelle aber unterschiedliche Parameter. - Beim Programmstart wird von jedem Modul eine Instanz erstellt und ein paar Basisinformationen (Modulname etc.) abgeholt und in eine Liste (Combobox), dem Anwender zur Auswahl gestellt. - Der Anwender wählt ein Modul aus und die Basisapplikation holt sich daraufhin von diesem Modul die verfügbaren Parameter und trägt sie in ein Config-Fenster ein. - Der Anwender ändert ggf. Optionen und klickt auf einen Start-Button. - Die Basisapplikation überreicht dem Modul die aktuellen Parameter als Strings über die einheitliche Aufrufschnittstelle und startet damit einen Ablauf. Gruß Philip Karl Käfer schrieb: > HTH, ??? :-)
Philip K. schrieb: > - Der Anwender wählt ein Modul aus und die Basisapplikation holt sich > daraufhin von diesem Modul die verfügbaren Parameter und trägt sie in > ein Config-Fenster ein. Sind die auswählbaren Parameter immer endlich (und ggf. auf eine mäßige Größe beschränkt), oder kommen auch welche vor in der Art "ganze Zahl" oder Gleitkommazahl zwischen -4.21 und +10.987"? Beliebige Dateinamen? Dann wäre "holt sich daraufhin von diesem Modul die verfügbaren Parameter" natürlich ganz anders zu interpretieren.
Ich habe in einem C++-Kurs mal für ein Art modularen Synthesizer mit flexiblen Modulen gearbeitet, die sich beim Pogramm registrieren konnten, damit die GUI bzw. das Konsolenprogramm was damit anfangen konnten. Als Beispiel der Anfang (die Includes mal weggelassen) eines solchen Moduls zur Hallerzeugung, jedes Modul registrierte seine Ein- und Ausgänge, damit die Module in der GUI miteinander verdrahtet und damit dann ein Ton erzeugt werden konnte:
1 | //Statisches Objekt von der eigenen Klasse wird initialisiert, dient der Modul-Registrierung
|
2 | CS_Gen_Hall& CS_Gen_Hall::own=*new CS_Gen_Hall((t_init)S_HALL); |
3 | |
4 | //Initialisierungskonstruktor zur Modul-Registrierung
|
5 | CS_Gen_Hall::CS_Gen_Hall(t_init id) |
6 | {
|
7 | CList_Module::Add_Modul(this,this->info(),id); |
8 | }
|
9 | |
10 | //normaler Konstruktor
|
11 | CS_Gen_Hall::CS_Gen_Hall(void) |
12 | {
|
13 | //Aus- und Eingänge des Hall-Moduls werden angelegt
|
14 | //hall ist Ausgang
|
15 | hall=CSig_Val::Output("Hall",this); |
16 | |
17 | //signal ist Eingang und liefert das Signal, auf das der Hall angewendet wird
|
18 | CSig_Val::Input(&signal,"Signal",this); |
19 | |
20 | //faktor ist die Abschwächung
|
21 | CSig_Val::Input(&faktor,"Abschwaech-Faktor",this); |
22 | |
23 | //delay ist die Verzögerung
|
24 | CSig_Val::Input(&delay,"Verzoegerung",this); |
25 | }
|
26 | |
27 | CS_Gen_Hall::~CS_Gen_Hall(void) |
28 | {
|
29 | }
|
30 | |
31 | //Info zurückgeben
|
32 | char * CS_Gen_Hall::info(void) |
33 | {
|
34 | return "Hallmodul"; |
35 | }
|
36 | |
37 | //Verweis auf neue Instanz zurückgeben
|
38 | CS_Modul * CS_Gen_Hall::instanz(void) { |
39 | return new CS_Gen_Hall(); |
40 | }
|
Sabine
Klaus Wachtler schrieb: > Sind die auswählbaren Parameter immer endlich (und ggf. auf eine mäßige > Größe beschränkt), oder kommen auch welche vor in der Art "ganze Zahl" > oder Gleitkommazahl zwischen -4.21 und +10.987"? Das sollte schon möglich sein. Deshalb dachte ich mir ja, dass ich eine Deskriptorklasse für jeden möglichen Datentyp (string, int float, bool, ...)implementiere, die u.a. Auskunft darüber gibt, welche Werte erlaubt sind.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.