I want to implement a RPC server. We can register some method on it. for example:
server.register("echo", [](){ cout << "hello" << endl; });
server.register("add", [](int a, int b, int &c){ c = a+b; });
server.register("print", [](std::string s){ cout << s << endl; });
To do this, I try to use a map to hold all methods. So a class can be hold any type of functions is needed. Here I use a empty base class, and design a derived templated class to hold actual function object. When i need use the method, I can use dynamic_cast base to certain derived.
Beside, I want to assemable c++ perfect forward.
So I write the code below (now all writed by myself):
#include <functional>
#include <string>
#include <memory>
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
class CallableBase {
public:
virtual ~CallableBase() {}
};
template <class Func>
class Callable: public CallableBase {
Func f_;
public:
Callable(Func func): f_(func) {
}
template <class ...Args>
void execute(Args&& ...args) {
f_(std::forward<Args>(args)...);
}
};
unordered_map<string, shared_ptr<CallableBase>> methods_;
template <class ...Args>
void execute(const std::string &name, Args&& ... args) {
using func_t = std::function<void(Args...)>;
auto f_ptr = dynamic_cast<Callable<func_t>*>(methods_[name].get());
f_ptr->execute(std::forward<Args>(args)...);
}
class TestObj {
public:
// TestObj() { cout << "Default Constructor. " << endl; }
TestObj() { }
TestObj(const TestObj &o) { cout << "Copy Constructor. " << endl; }
TestObj(TestObj &&o) { cout << "Move Constructor. " << endl; }
~TestObj() = default;
void Nap() const { cout << a << endl; }
int a = 2;
};
int main() {
methods_["echo"] = std::make_shared<Callable<std::function<void(int s)>>>([](int s){ cout << s << endl; });
methods_["add"] = std::make_shared<Callable<std::function<void(int,int,int&)>>>([](int a, int b, int& c){ c= a+b; });
methods_["sub"] = std::make_shared<Callable<std::function<void(int,int,int&)>>>([](int a, int b, int& c){ c= a-b; });
int outer = 1;
methods_["modify_outer"] = std::make_shared<Callable<std::function<void(int,int)>>>([&outer](int a, int b){ outer = a+b; });
execute("modify_outer", 1, 2);
cout << outer << endl;
execute("echo", 12);
int c = 0;
execute("add", 2, 3, c);
cout << c << endl;
execute("sub", 2, 3, c);
cout << c << endl;
return 0;
}
However, I find it can only use some build-in type, such as int, float.
std::string, or TestObj will lead to zsh: segmentation fault.
I don't know what happened, and how to fixed it。。。。