Last Updated: February 25, 2016
·
518
· themichael'tips

C++11 for mapping methods

Introduction

Here is showed a snippet of code that allow to store class's methods in a map.
<br>In addition we will prefer inheritance instead of polymorphism when is possible.
<br>To do things simply, the methods will use int f(int) signature.

#include <iostream>
#include <functional>
#include <unordered_map>

/* First: describe in a generic way the class that owns the function */
template <class T> using magic_method = std::function<int(T*,int)>;

/* Second: define the common class used to call the stored methods */
struct AbstractExec {
    virtual int exec(const std::string& method, int param) = 0;
    ~AbstractExec() {}
};

/* Third: we need a template in order to deal with the custom magic_method type */
template <class T>
struct RealExec : public AbstractExec {

  virtual void register_method(const std::string&name, magic_method<T> f) {
    map[name] = f;
  }

  virtual int exec(const std::string& method, int param) {
    if (map.find(method) == map.end())
      throw std::string("Method " + method + " does not exist");

    return map[method](dynamic_cast<T*>(this),param);
  }

  protected:
  std::unordered_map<std::string, magic_method<T>> map;
};

Let's look at a simple use:

struct A : public RealExec<A> {
  A() {
    register_method("m1", &A::m1);
  }

  int m1(int p) {
    std::cout << "<A::m1()>";
    return p;
  }

};

struct B : public RealExec<B> {
  B()  {
   register_method("m1", &B::m1);
   register_method("m2", &B::m2);
 }

  int m1(int p) {
    std::cout << "<B::m1()>";
    return p+1;
  }

  int m2(int p) {
    std::cout << "<B::m2()>";
    return p+2;
  }
};

Finally, we can use the code in this way:

int main(void) {
  AbstractExec *abstract;
  A a;
  B b;

  abstract = &a;
  abstract->exec("m1", 1);
  a.exec("m1", 1);

  abstract = &b;
  abstract->exec("m1", 2);
  abstract->exec("m2", 3);

  return 0;
}