[C++] Registrieren von Methoden - std::function, lambdas,...

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.

[C++] Registrieren von Methoden - std::function, lambdas,...

Beitragvon smurfer » 21.08.2016, 21:22

Hallo zusammen,

mir fiel es nicht ganz leicht, einen passenden Betreff zu finden, und ich hoffe somit, dass die folgende Erläuterung verständlich ist: Ich möchte bei einer Klasse (bzw. deren Instanz) Methoden anderer Klassen (Module) registrieren, d.h. bekannt geben, dass ein Modul eine Methode zur Verfügung stellt und Zugriff auf diese bieten.
Die erstgenannte Klasse ist die Schnittstelle zu Webclient, Lua-Scripting und weiteren internen Modulen, eine abstrakte Schicht über der darunterliegenden Engine. Ein Lua-Script soll nun genau wie ein Webclient Methoden nutzen können (lesend wie schreibend), also bespielsweise get_objects oder set_time. Diese werden von den Engine-Modulen zur Verfügung gestellt und bei der Schnittstelle registriert.

So sagt ein Datenmanager etwas wie
Code: Ansicht erweitern :: Alles auswählen
register("get_objects",...)

ein Systemmanager sinngemäß
Code: Ansicht erweitern :: Alles auswählen
register("set_time",...)

Wie löse ich so etwas am Besten? Momentan schwebt mir etwas vor wie eine unordered_map in der Schnittstelle, die z.B. einen String als Schlüssel registriert und dahinter eine Methode über ein Lambda mittels std::function ablegt. Allerdings sehe ich noch nicht, wie ich mit verschiedenen Parametern, Rückgabewerten etc. umgehen soll. Dafür wieder abstrakte Interfaces scheint mir zu umständlich, gibt es dafür eine einfache Lösung oder ein Best-Practice?

Viele Grüße, smurfer
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 22.08.2016, 20:05

Noch ein Nachtrag: Mir würde es schon helfen zu wissen, wonach ich genau suchen muss. Bislang war ich mit function/method registration, variadic functions/templates, lambda, functor, variable number of parameters, callback ... in diversen Kombinationen im Kontext C++ nicht sonderlich weit gekommen.

Hier mal ein kurz zusammen gehackter Ausschnitt ohne Anspruch auf finales Design, der mit einer bestimmten Art von Funktion (kein Rückgabewert, keine Parameter) das macht, was ich möchte:
Code: Ansicht erweitern :: Alles auswählen

#ifndef COM_INTERFACE_H
#define COM_INTERFACE_H

//--- Standard header --------------------------------------------------------//
#include <functional>
#include <unordered_map>

/// Map of functions, accessed by name
typedef std::unordered_map<std::string, std::function<void(void)>> RegisteredFunctionsType;

////////////////////////////////////////////////////////////////////////////////
///
/// \brief Class providing an interface to the engine
///
////////////////////////////////////////////////////////////////////////////////
class CComInterface
{
   
    public:

        //--- Methods --------------------------------------------------------//
        void call(const std::string& _strName)
        {
            METHOD_ENTRY("CComInterface::call")
            if (m_RegisteredFunctions.count(_strName) != 0)
                m_RegisteredFunctions[_strName]();
            else
            {
                WARNING_MSG("Com Interface", "Unknown function <" << _strName << ">. ")
            }
        }
        bool registerFunction(const std::string& _strName, const std::function<void(void)>& _Function)
        {
            METHOD_ENTRY("CComInterface::registerFunction")
            m_RegisteredFunctions[_strName] = _Function;
            return true;
        }
    private:
       
        RegisteredFunctionsType m_RegisteredFunctions; ///< Registered functions provided by modules
     
};
#endif // COM_INTERFACE_H


Code: Ansicht erweitern :: Alles auswählen

void quit()
{
    METHOD_ENTRY("quit")
    g_bDone = true;
}

int main(int argc, char *argv[])
{
    [...]
   
    CComInterface ComInterface;
    ComInterface.registerFunction("quit", quit);

    [...]

    // Quit the program
    ComInterface.call("quit");
}


Diese Funktionalität hätte ich nun gerne mit beliebigen Parametern und Rückgabewerten, aber außer ein Interface, welches für jede Art von Aufruf abgeleitet werden muss, ähnliches gilt für Funktoren, oder reiner C-Code, fällt mir bislang keine Lösung ein. Auch Template-Lösungen wie std::tuple benötigen für jeden Parametersatz andere Templateparameter und scheiden daher auch aus, oder übersehe ich etwas?

Beste Grüße, smurfer
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon Gene » 23.08.2016, 01:40

Hi

Leider kann ich dir keinen Suchbegriff nennen nachdem Du suchen könntest. Aber es dürfe lösbar sein. Der trick ist über geschickte Vererbung das zu machen.

Code: Ansicht erweitern :: Alles auswählen

class BaseCallbackFunction {
public:
  virtual ~BaseFunction() {}
};

template <typename ...Args>
class CallbackFunction : public BaseCallbackFunction {
  std::function<void(Args...)> mFunction;
public:
 void call(Args ....args) {
    mFunctions(args...);
  }
};

typedef std::unordered_map<std::string, std::unique_ptr<BaseCallbackFunction>> RegisteredFunctionsType;

[]

        template<typename ...Args>
        void CComInterface::call(const std::string& _strName, Args... args)
        {
            METHOD_ENTRY("CComInterface::call")
            if (m_RegisteredFunctions.count(_strName) != 0)
                auto ptr = dynamic_cast<CalbackFunction<Args...>*>(m_RegisteredFunctions[_strName].get());
                if (ptr != nullptr ){
                  ptr->call(args...);
                } else {
                WARNING_MSG("Com Interface", "Known function with different signature <" << _strName << ">. ")
                }
            else
            {
                WARNING_MSG("Com Interface", "Unknown function <" << _strName << ">. ")
            }
        }
 
Zuletzt geändert von Gene am 24.08.2016, 10:41, insgesamt 1-mal geändert.
Gene
 
Beiträge: 25
Registriert: 22.05.2003, 11:26

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 23.08.2016, 09:25

Hallo Gene,

vielen Dank schon mal! Ich werde die Variante, sobald ich wieder am Rechner zuhause bin, ausprobieren.

Beste Grüße
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon Helmut » 23.08.2016, 14:26

Wenn es um Lua geht kannst du dir auch luabind anschauen.
Insgesamt würde ich aber diese ganzen Indirektionen versuchen zu vermeiden. Sowas zu Debuggen macht keinen Spaß.
Helmut
Establishment
 
Beiträge: 228
Registriert: 11.07.2002, 15:49
Wohnort: Bonn

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon NytroX » 23.08.2016, 23:02

Ich würde mir an deiner Stelle mal ChaiScript anschauen.

Die benutzen C++11/14 magic um das hinzubekommen; sieht dann so aus:

Code: Ansicht erweitern :: Alles auswählen

#include <chaiscript/chaiscript.hpp>

std::string helloWorld(const std::string &t_name) {
  return "Hello " + t_name + "!";
}

int main() {
  chaiscript&#058;:ChaiScript chai;
  chai.add(chaiscript&#058;:fun(&helloWorld), "helloWorld");

  chai.eval(R"(
    puts(helloWorld("
Bob"));
  )"
);
}
 


Link zur Homepage: http://chaiscript.com
Source für das binding: https://github.com/ChaiScript/ChaiScript/blob/develop/include/chaiscript/dispatchkit/register_function.hpp
NytroX
Establishment
 
Beiträge: 137
Registriert: 03.10.2003, 12:47

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 24.08.2016, 09:17

Hallo zusammen,

Helmut, danke für den Hinweis. Es ging mir allerdings nicht primär um Lua-Bindings, Lua ist letztlich nur ein Nutzer der Schnittstelle. Im Endeffekt möchte ich kein ausgewachsenes internes Scripting, sondern lediglich eine Art flexible Functors. Als Ergänzung, es gibt eine ganz nette Übersicht und Bewertung der diversen Lua-Binding-Bibliotheken: http://realmensch.org/blog/fun-lua-bindings.

NytroX, vielen Dank, sieht sehr interessant aus. Selbst wenn ich ChaiScript nicht unmittelbar einbinden sollte (siehe obigen Kommentar an Helmut, es sollte keine komplette Scripting-Engine sein), lassen sich bestimmt interessante Implementierungsdetails aus dem Code lesen.

Beste Grüße
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon dot » 24.08.2016, 09:57

Nur mal rein prinzipiell: Was ist denn genau das Problem mit std::function?
Benutzeravatar
dot
Michael Kenzel
Establishment
 
Beiträge: 1629
Registriert: 06.03.2004, 19:10

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 24.08.2016, 10:07

Hi dot,

std::function an sich ist kein Problem, das nutze ich ja auch -- siehe Beispiel zweiter Post. Allerdings muss ich dort nach meinem Verständnis fest die Templateparameter angeben, was spätestens dann schwierig wird, wenn ich die Funktionen mit verschiedenen Parametern und Rückgabewerten in der unordered_map speichere. So zumindest meinem naiven Gedanken nach.
Das Beispiel im zweiten Post funktioniert soweit, allerdings eben nur für einen Funktions- oder per Lambda-Delegate einen Methodentyp.

War das die Frage? Ich bin für jeden Vorschlag offen, mit manchen der neuen (C++11-)Möglichkeiten bin ich noch nicht so dicke ;)

Edit: Zu dem Thema, Gene, wie sähe denn dann nach Deinem Beispiel die Deklaration der map als Member aus und fehlt nicht die Ableitung von der Basisklasse beim spezialisierten Callback? So ganz habe ich es noch nicht raus.
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon Gene » 24.08.2016, 10:38

Hi smurf

(Dies ist nicht bezogen auf deinen Edit, den hab ich erst jetzt gesehen)

Dir fehlt Überladung von Funktionen? Das kann man damit auch implementieren. Das Problem ist natürlich hier nur die unorderd_map:
Code: Ansicht erweitern :: Alles auswählen
 typedef std::unordered_map<std::string, std::unique_ptr<BaseCallbackFunction>> RegisteredFunctionsType;


Hier hab ich unterschiedliche Lösungsvorschläge:
1. mit einem Hilfsvektor
Code: Ansicht erweitern :: Alles auswählen
 typedef std::unordered_map<std::string, std::vector<std::unique_ptr<BaseCallbackFunction>>> RegisteredFunctionsType;

In diesem fall müssten man durch alle einträge in std::vector mit dynamic_cast testen um den richtigen eintrag herrauszubekommen.

2. mit einem anderen key für die unordered_map:
Code: Ansicht erweitern :: Alles auswählen
 typedef std::unordered_map<std::pair<std::string, size_t>, std::unique_ptr<BaseCallbackFunction>> RegisteredFunctionsType;
[]
        template<typename ...Args>
        void CComInterface::call(const std::string& _strName, Args... args)
        {
            std::pair<std::string, size_t> key;
            key.first = _strName;
            key.second = typeid(CallbackFunction<Args....>).hash_code();
            if (m_RegisteredFunctions.count(key) != 0)
            []
 


schöne Grüße Gene
Zuletzt geändert von Gene am 24.08.2016, 10:41, insgesamt 1-mal geändert.
Gene
 
Beiträge: 25
Registriert: 22.05.2003, 11:26

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon Gene » 24.08.2016, 10:40

Hi

Ja die Ableitung fehlt. Ich korrigiere das oben im Post.
Was meinst du mit "Map" alse "Member?
Gene
 
Beiträge: 25
Registriert: 22.05.2003, 11:26

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon dot » 24.08.2016, 10:48

smurfer hat geschrieben:Hi dot,

std::function an sich ist kein Problem, das nutze ich ja auch -- siehe Beispiel zweiter Post. Allerdings muss ich dort nach meinem Verständnis fest die Templateparameter angeben, was spätestens dann schwierig wird, wenn ich die Funktionen mit verschiedenen Parametern und Rückgabewerten in der unordered_map speichere. So zumindest meinem naiven Gedanken nach.

Nun, wenn du die Signatur der Funktion nicht kennst, kannst du sie aber auch nie aufrufen. Von da her ist mir nicht ganz klar, was genau der Sinn davon sein sollte, eine Funktion unbekannter Signatur zu "speichern"... ;)

PS: Ich frag nur blöd nach weil das, was du hier offenbar zu basteln suchst, mir nach einer unglaublich komplizierten Lösung für ein Problem aussieht, das man sich besser gar nicht erst machen würde... ;)
Zuletzt geändert von dot am 24.08.2016, 10:50, insgesamt 1-mal geändert.
Benutzeravatar
dot
Michael Kenzel
Establishment
 
Beiträge: 1629
Registriert: 06.03.2004, 19:10

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 24.08.2016, 10:49

Gene hat geschrieben:Hi

Ja die Ableitung fehlt. Ich korrigiere das oben im Post.
Was meinst du mit "Map" alse "Member?


Danke und das mit dem Member hat sich erledigt.
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 24.08.2016, 10:55

dot hat geschrieben:Nun, wenn du die Signatur der Funktion nicht kennst, kannst du sie aber auch nie aufrufen. Von da her ist mir nicht ganz klar, was genau der Sinn davon sein sollte, eine Funktion unbekannter Signatur zu "speichern"... ;)

Dem will und kann ich nicht widersprechen :D. Ich war bislang davon ausgegangen, die Signatur (wieder eine Vokabel gelernt :)) bei der Deklaration der unordered_map kennen zu müssen. Falls ich Genes Vorschlag soweit richtig interpretiere, ist das nicht somit nicht mehr der Fall, dann muss ich die Signatur nur noch an der Stelle oder in dem Modul kennen, welches die Methode/Funktion anbieten und registrieren möchte -- das ist ja völlig in Ordnung.
Ich muss noch einmal die Ruhe und Zeit finden, einzubinden und in meinem Kontext zu testen, wahrscheinlich ist es dann damit gelöst. Vielen Dank Euch soweit.
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 24.08.2016, 10:59

dot hat geschrieben:PS: Ich frag nur blöd nach weil das, was du hier offenbar zu basteln suchst, mir nach einer unglaublich komplizierten Lösung für ein Problem aussieht, das man sich besser gar nicht erst machen würde... ;)

Mag auch sein, blöde Gegenfrage: Wie kann ich es unkompliziert machen :)?

Mir geht es letztlich darum, dass ich von außen (Lua und andere Clients) Zugriff auf Teile der Engine benötige, die in verschiedenen Modulen liegen (Physik, System,...) und auch voraussichtlich recht häufig erweitert werden. Da sah ich es als komfortable Lösung, bereitgestellten Zugriff in der dargestellen Form möglichst schnell zu registrieren.
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon dot » 24.08.2016, 11:04

smurfer hat geschrieben:
dot hat geschrieben:Nun, wenn du die Signatur der Funktion nicht kennst, kannst du sie aber auch nie aufrufen. Von da her ist mir nicht ganz klar, was genau der Sinn davon sein sollte, eine Funktion unbekannter Signatur zu "speichern"... ;)

Dem will und kann ich nicht widersprechen :D. Ich war bislang davon ausgegangen, die Signatur (wieder eine Vokabel gelernt :)) bei der Deklaration der unordered_map kennen zu müssen.

Musst du auch. Die Frage ist: Wieso musst du einen Haufen Funktionen, die nichts miteinander zu tun haben, in der selben Map speichern?

smurfer hat geschrieben:Mir geht es letztlich darum, dass ich von außen (Lua und andere Clients) Zugriff auf Teile der Engine benötige, die in verschiedenen Modulen liegen (Physik, System,...) und auch voraussichtlich recht häufig erweitert werden. Da sah ich es als komfortable Lösung, bereitgestellten Zugriff in der dargestellen Form möglichst schnell zu registrieren.

Deine Engine muss doch irgendein Interface haben!? Wenn du ein Lua Binding willst, musst du eben ein Lua Binding bauen. Was genau eine Map von Funktionspointern da helfen soll, ist mir ein bisschen ein Rätsel... ;)
Benutzeravatar
dot
Michael Kenzel
Establishment
 
Beiträge: 1629
Registriert: 06.03.2004, 19:10

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon Gene » 24.08.2016, 15:03

dot hat geschrieben:
smurfer hat geschrieben:
dot hat geschrieben:Nun, wenn du die Signatur der Funktion nicht kennst, kannst du sie aber auch nie aufrufen. Von da her ist mir nicht ganz klar, was genau der Sinn davon sein sollte, eine Funktion unbekannter Signatur zu "speichern"... ;)

Dem will und kann ich nicht widersprechen :D. Ich war bislang davon ausgegangen, die Signatur (wieder eine Vokabel gelernt :)) bei der Deklaration der unordered_map kennen zu müssen.

Musst du auch. Die Frage ist: Wieso musst du einen Haufen Funktionen, die nichts miteinander zu tun haben, in der selben Map speichern?


Also natürlich musst du die Signatur der unordered_map kennen. Aber es ist nicht notwendig die Signatur der Funktionen zu kennen, die in der unordered_map gespeichert werden.
Diese müssen bekannt sein wenn die Funktion zur map hinzugefügt wird und wenn die Funktion aus der map aufgerufen wird. Dies ist aber in beiden Fällen trivialerweise gegeben.
Gene
 
Beiträge: 25
Registriert: 22.05.2003, 11:26

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 24.08.2016, 20:14

dot hat geschrieben:Musst du auch. Die Frage ist: Wieso musst du einen Haufen Funktionen, die nichts miteinander zu tun haben, in der selben Map speichern?

Jetzt geraten wir wieder in die gleiche Richtung wie neulich bei der -- durchaus interessanten -- Diskussion zu Downcasts ;) . Falls "nichts miteinander zu tun haben" für Dich über die Signatur definiert ist, stimmt es natürlich. Allerdings gehören die Funktionen rein logisch für mich sehr wohl zusammen. So ist z.B. ein setRadius für mich auf gleicher logischer Ebene wie ein setPosition, dennoch unterscheiden sich die Parameter und damit die Signatur. Die Umsetzung sind sprachliche Mittel zum Zweck. Dafür die passenden zu finden, ist genau der Anlass meiner Anfrage. Im Prinzip gefällt mir Genes Lösung schon recht gut.

dot hat geschrieben:Deine Engine muss doch irgendein Interface haben!? Wenn du ein Lua Binding willst, musst du eben ein Lua Binding bauen. Was genau eine Map von Funktionspointern da helfen soll, ist mir ein bisschen ein Rätsel... ;)

Ich möchte im Idealfall, dass kein Nutzer der Methoden etwas über die Module wissen muss, von denen diese kommen, sondern nur, dass es ein zentrales Kommuniktationsinterface gibt. Zu Deiner Anmerkung, das Lua-Modul würde sich entsprechend direkt and das Interface, nicht an dessen Module hängen.
Nennen wir sie mal Backend- und Frontend-Module:

Server

Backend:.......Simulation, Physik, System, ...
..............................\.............|......../
................................ComInterface
............................/............|...............\
Frontend:..........Lua,.. Netzwerk,... lokale Grafik
................................./.......|........\
Client..................Web, Terminal, GUI

Z.B. sollte das Lua-Modul Zugriff auf Objekte (des Physikmoduls) haben, gleichzeitig aber auch auf Aspekte des Simulationsmoduls, wie Simulationsfrequenz etc., sowie auf das System (Programmende, Pause). Gleiches gilt für das Netwerkmodul, welches all diese Informationen zu einem Terminal-Client oder einem grafischen Client schickt.

Ich hoffe es ist etwas klarer geworden.

Edit: Kurzer Nachtrag zum Verständnis: Das ComInterface könnte genauso eine Klasse mit lauter Methoden sein, die die Anfragen einfach nur weiterleiten (das wären dann wohl delegates?!). Dann müsste das Interface alle Backend-Module kennen. Vom Gefühl her fand ich es sinnvoller, dass alle Module das Interface kennen und jeder melden kann, was er bereitstellt. Ein Grund für das ComInterface war zudem, dass es an einer zentralen Stellen einen Datenspeicher gibt, der für potentielle Frontends einen konsistenten Zustand bereit hält, unabhängig von im Hintergrund laufenden Berechnungen. Auf genau den greift das ComInterface zu, so dass die Frontends und letztlich Clients genau mit diesem konsistenten Zustand arbeiten können.

Edit 2: Zurzeit bin ich allerdings ein wenig zwiegespalten, da bei Genes Lösung für jede Methode ein Helferlein geschrieben werden müsste, dafür an der gefühlt richtigen Stelle. Ich suche einfach etwas, womit ich mit einem Kommando dem Interface mitteilen kann: "Du brauchst XY? Habe ich schon, stelle ich Dir bereit" und das sinngemäß mittels register(etwas_schon_vorhandenes).
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon Gene » 25.08.2016, 11:10

smurfer hat geschrieben:[...]
Edit 2: Zurzeit bin ich allerdings ein wenig zwiegespalten, da bei Genes Lösung für jede Methode ein Helferlein geschrieben werden müsste, dafür an der gefühlt richtigen Stelle. Ich suche einfach etwas, womit ich mit einem Kommando dem Interface mitteilen kann: "Du brauchst XY? Habe ich schon, stelle ich Dir bereit" und das sinngemäß mittels register(etwas_schon_vorhandenes).


An welcher Stelle benötigst du Helferlein? Man benötigt man einen kleinen Lambdaausdruck um Methoden von Klassen zu regestrieren. Für freie/globale Funktionen ist das nicht notwendig.
Gene
 
Beiträge: 25
Registriert: 22.05.2003, 11:26

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 28.08.2016, 15:03

Hallo zusammen,

Gene, Du hast Recht, die Helferlein halten sich in Grenzen. Ich habe jetzt einmal Zeit gefunden, deinen Ansatz bei mir zu implementieren und es funktioniert wie gewünscht, danke :) . Der Registrierungsaufruf bleibt dank Lambdas und entsprechendem Constructor recht übersichtlich, hier ein Bsp. direkt aus dem Code:
Code: Ansicht erweitern :: Alles auswählen
ComInterface.registerFunction("cycle_camera",new CallbackFunction<>([&](){pVisualsManager->cycleCamera();}));


Ich werde bestimmt noch auf die ein oder andere Hürde stoßen, bis dahin passt es soweit, danke an alle für die guten Ideen und interessanten Anmerkungen.

Grüße, smurfer
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon odenter » 31.08.2016, 15:05

Wenn ich Dich richtig verstanden habe willst Du eine Liste von Kommandos erzeugen und dritten Ermöglichen diese Kommandos zu starten bzw. auszuführen.

Guck Dir doch mal die Quellen hiervon an:
http://www.oocities.org/standard_template/irrconsole/

Dies ist eine Ingameconsole, also Befehl eintippen und dann wird etwas ausgeführt.
Als Benutzer dieser Befehle muss ich nicht wissen wie die intern funktionieren. Die machen halt was, ich kann mir aber z.B. die Beschreibung anzeigen lassen welche der Programmierer eingepflegt hat.
Es muss allerdings für jedes Kommando eine Klasse erzeugt werden. Im Vergleich zu Deinem Ansatz klingt das erstmal nach mehr Arbeit, ich persönlich finde es allerdings besser. Vor allem was Fehlersuche und Behebung angeht. Außerdem kann man so den Zugriff auf die "internen" Methoden nochmal kapseln/wrappen what ever man machen will.

Die Registrieung eines Kommandos bei mir sieht wie folgt aus:
Code: Ansicht erweitern :: Alles auswählen

        void irrConsole::LoadDefaultCommands(irr::IrrlichtDevice* device)
{
        ICommand* cmd = 0;

        cmd = new irrConsoleCommandEcho;
        RegisterCommand(cmd);
       
        cmd = new irrConsoleCommandHelp;
        RegisterCommand(cmd);

        cmd = new irrConsoleCommandList;
        RegisterCommand(cmd);
       
        cmd = new irrConsoleCommandDriverInfo(Helper::IrrlichtHelper::GetInstance()->Device());
        RegisterCommand(cmd);

        cmd = new irrConsoleCommandExit;
        RegisterCommand(cmd);

        cmd = new irrConsoleCommandQuit;
        RegisterCommand(cmd);

  cmd = new irrConsoleCommandSetApplicationVariable;
  RegisterCommand(cmd);
}
 


ausgeführt wird es wie folgt:
Code: Ansicht erweitern :: Alles auswählen

void IDispatcher::dispatch(const String cmdName, const irr::core::array<String>& args, IMessageSink* pOutput)
{
  std::map<String, ICommand*>::iterator iter = commandTable.find(cmdName);
        if(iter != commandTable.end())
        {
                try
                {
                        iter->second->invoke(args, this, pOutput);
                        pOutput->AppendMessage(L"");
                }
                catch(irrConsoleError& err)
                {
                        String wstr = L"error of type ";
                        wstr += err.GetType();
                        wstr += L" in invoking command [";
                        wstr += cmdName;
                        wstr += L"]";
                        pOutput->logError(wstr);
                        pOutput->AppendMessage(err.GetMessage());
                }
                catch(std::exception& ex)
                {
                        String wstr = L"error in invoking command [";
                        wstr += cmdName;
                        wstr += L"]";
                        pOutput->logError(wstr);
                        pOutput->AppendMessage(gf_ToString(ex.what()));
                }
        }
        else
        {
                String wstr = L"command [";
                wstr += cmdName;
                wstr +=L"] is not a valid command";
                pOutput->logError(wstr);
                pOutput->AppendMessage(L"for a list of messages type \"help\" or \"list\"");
        }
}
 


Befehl echo
Code: Ansicht erweitern :: Alles auswählen

class irrConsoleCommandEcho : public ICommand
{
public:
        irrConsoleCommandEcho();
        virtual ~irrConsoleCommandEcho();
        bool invoke(const irr::core::array<String>& args, IDispatcher* pDispatcher, IMessageSink* pOutput);
};


irrConsoleCommandEcho::irrConsoleCommandEcho() : ICommand(L"echo")
{
        SetUsage(L"echo <string>");
        AddDescLine(L"This command echoes the given string to console");
}

irrConsoleCommandEcho::~irrConsoleCommandEcho()
{
}

bool irrConsoleCommandEcho::invoke(const irr::core::array<String>& args, IDispatcher* pDispatcher, IMessageSink* pOutput)
{
        if(args.size() >= 1)
        {
                String wstr = args[0];
                for(irr::u32 i = 1; i < args.size(); i++)
                {
                        wstr += L" ";
                        wstr += args[i];
                }
                pOutput->AppendMessage(wstr);
        }
        return true;
}
 


Befehl driver_info
Code: Ansicht erweitern :: Alles auswählen

class irrConsoleCommandDriverInfo : public ICommand
{
public:
        irrConsoleCommandDriverInfo(irr::IrrlichtDevice *pDevice);
        virtual ~irrConsoleCommandDriverInfo();
        bool invoke(const irr::core::array<String>& args, IDispatcher* pDispatcher, IMessageSink* pOutput);
private:
        irr::IrrlichtDevice *device;
};
irrConsoleCommandDriverInfo::irrConsoleCommandDriverInfo(irr::IrrlichtDevice *pDevice) : ICommand(L"driver_info"), device(pDevice)
{
        SetUsage(L"driver_info");
        AddDescLine(L"This command prints some info about the engine");

}
irrConsoleCommandDriverInfo::~irrConsoleCommandDriverInfo()
{
        device = 0;
}
bool irrConsoleCommandDriverInfo::invoke(const irr::core::array<String>& args, IDispatcher* pDispatcher, IMessageSink* pOutput)
{
        if(device)
        {
                irr::video::IVideoDriver* driver = device->getVideoDriver();
                String wstr = L" Irrlicht Version : ";
                wstr += gf_ToString(device->getVersion());
                pOutput->AppendMessage(wstr);

                // TODO: prüfen
                //wstr = L" OS Version : ";
                //wstr += device->getOSOperator()->getOperatingSystemVersion();
                //pOutput->AppendMessage(wstr);

                wstr = L" Display Driver : ";
                wstr+= device->getVideoDriver()->getName();
                pOutput->AppendMessage(wstr);

                wstr=L"";
                return true;
        }
        else
        {
                throw irrConsoleError(L"No valid irrlicht device detected!!");
        }
}
 


Aufruf z.B. so:
Code: Ansicht erweitern :: Alles auswählen

\echo 12345
\echo Fuchs
\driver_info

\help driver_info // gibt hilfe zu Befehl driver_info aus
\help echo // gibt Hilfe zu Befehl echo aus
odenter
Establishment
 
Beiträge: 189
Registriert: 26.02.2009, 12:58

Re: [C++] Registrieren von Methoden - std::function, lambdas

Beitragvon smurfer » 06.09.2016, 12:03

Hi odenter, danke für den ausführlichen Hinweis, werde ich mir auch bei Gelegenheit näher anschauen. Viele Grüße
smurfer
 
Beiträge: 60
Registriert: 25.02.2002, 15:55


Zurück zu Algorithmen und Datenstrukturen

Wer ist online?

Mitglieder in diesem Forum: Google [Bot] und 1 Gast