[C++] Callback Klasse - Funktionsaufruf per Funktionsname mit unterschiedlichen Parameter

#1
Hallo Community!

Benötige für ein Projekt eine Klasse, die die Eigenschaft besitzt, dass per Funktionsname (std::string) eine jeweilige Funktion aufruft.
Das Ganze aber mit unterschiedlichen Parameter.

Hab mal folgendes Codesnippet auf Stack Overflow gefunden:
C++:
#include <iostream>
#include <map>

int add(int i, int j) { return i+j; }
int sub(int i, int j) { return i-j; }

typedef int (*FnPtr)(int, int);

int main() {
    // initialization:
    std::map<std::string, FnPtr> myMap;
    myMap["add"] = add;
    myMap["sub"] = sub;

    // usage:
    std::string s("add");
    int res = myMap[s](2,3);
    std::cout << res;
}
Quelle: https://stackoverflow.com/questions/19473313/how-to-call-a-function-by-its-name-stdstring-in-c

Problem bei diesem Code wäre, dass ich alle möglichen Funktionspointer definieren müsste.
Ich will das aber nicht so machen.

Könnte das eventuell mit einem Template und VARG funktionieren, oder hat wer eine andere Idee
wie ich das lösen könnte?

Vorweg vielen Dank!
 
#4
Ich hab eine funktionierende Klasse :)

Will ich euch nicht vorenthalten:
C++:
#include <iostream>
#include <map>
#include <string>

int func0(int x)
{
    std::cout << x << std::endl;
}

int func1(int x, int y)
{
    std::cout << (x + y) << std::endl;
}

template <class... Args>
struct MapHolder{
    static std::map<std::string, int (*)(Args...)> CallbackMap;
};

template <class... Args>
std::map<std::string, int (*)(Args...)> MapHolder<Args...>::CallbackMap;

class Callback {
public:
    template <class ...Args>
    void RegisterFunction(std::string name, int (*func)(Args...)) {
        MapHolder<Args...>::CallbackMap[name] = func;
    }
    
    template <class ...Args>
    int ExecuteFunction(std::string name, Args &&... args) {
        return MapHolder<Args...>::CallbackMap[name](std::forward<Args>(args)...);
    };
};

int main(int argc, char *argv[])
{
    Callback cb;
    
    cb.RegisterFunction("func0", &func0);
    cb.RegisterFunction("func1", &func1);
    
    cb.ExecuteFunction("func0", 42);
    cb.ExecuteFunction("func1", 42, 42);
    return 0;
}
Ausgabe:
Code:
42
84
 
#5
Das ist aber doch was aehnlich es wie in den anderen Links und da wolltest du ja nicht jede Funktion einzeln registrieren, und nun hast du es halt nur in eine Klasse gepackt.
Darueber hinaus sehe ich ein Problem wenn der Rueckgabewert mal nicht int ist, dann hast du beim Aufruf von Callback::ExecuteFunction() ein Problem.
Da muesstest du IMHO noch etwas weiter rumschrauben, wenn es wirklich generisch sein soll.
Von variablen Paramterlisten mal ganz zu schweigen.
Da faellt mir dann spontan Command- und Strategy-Pattern ein.

Cheers

Fluffy
 
#6
Das ist aber doch was aehnlich es wie in den anderen Links und da wolltest du ja nicht jede Funktion einzeln registrieren, und nun hast du es halt nur in eine Klasse gepackt.
Ja. Das war mir vorher aber nicht ganz klar, wie das lin C++ lösen kann. Habe mich mit Templates und Varadic Arguments vorher nicht so auseinandergesetzt. Benutze C++ eher selten, will aber mein Wissensdefizit hier nachholen.
Darueber hinaus sehe ich ein Problem wenn der Rueckgabewert mal nicht int ist, dann hast du beim Aufruf von Callback::ExecuteFunction() ein Problem.
Da muesstest du IMHO noch etwas weiter rumschrauben, wenn es wirklich generisch sein soll.
Das ist mir klar. Mir reicht aber derzeit für mein Projekt ein fixer Rückgabewert.
Von variablen Paramterlisten mal ganz zu schweigen.
Ist mir jetzt nicht so wichtig. Da ich diese relativ selten benutze. Wäre aber durchaus noch interessant zu wissen, wie das lösbar wäre.
Da faellt mir dann spontan Command- und Strategy-Pattern ein.

Cheers

Fluffy
Bitte um Entschuldigung, wenn ich mein Vorhaben etwas falsch erklärt habe. Aber das war es tatsächlich was ich benötigte.
Mag jetzt für einen erfahrenen C++ Entwickler nicht ein Problem darstellen. Für mich Anfangs allerdings schon.
 
Oben