I have implemented a class called MethodMap
that allows me to store member function pointers of a class and call them at runtime using a key string. The member function can take any parameters or not at all. The class looks like this:
template <typename T, typename... Args>
class MethodMap {
private:
std::unordered_map<std::string, std::function<void(T*, Args...)>> method_map;
public:
void Insert(const std::string& key, void (T::* method)(Args...)) {
method_map[key] = [method](T* obj, Args... args) { (obj->*method)(args...); };
}
void Call(const std::string& key, T* instance, Args&&... methodArgs) const {
auto it = method_map.find(key);
if (it != method_map.end()) {
auto& func = it->second;
// use tuple to store and forward the arguments
std::tuple<Args...> arg_tuple(std::forward<Args>(methodArgs)...);
std::apply(func, std::tuple_cat(std::make_tuple(instance), arg_tuple));
return;
}
std::cerr << "Error: method '" << key << "' not found" << std::endl;
}
};
The Insert
method inserts a member function pointer to the map, and the Call
method calls the member function with the given key and arguments.
It works well, but I realized that I need to create a different instance of MethodMap
for every member function pointer that takes different arguments. For example, if I have the following member functions:
class MyClass {
public:
void Method1(int x);
void Method2(double d);
void Method3(int x, const std::string& s);
void Method4();
};
I would need to create a different instance of MethodMap
for each member function pointer because they have different argument lists. For example:
MethodMap<MyClass> methodmap;
MyClass myClass;
methodmap.Insert("key", &MyClass::Method4);
methodmap.Call("key", &myClass);
MethodMap<MyClass, int> methodmapWithParameters;
methodmapWithParameters.Insert("key", &MyClass::Method1);
methodmapWithParameters.Call("key", &myClass, 1);
Is there a way to handle this with a single instance of MethodMap
?
I did encounter similar questions, but in all of them the parameters given were always the same and I'm having trouble to generalize this myself.