Here's an implementation that uses any
(demo):
#include <iostream>
#include <functional>
#include <map>
#include <string>
#include <any>
using namespace std;
class server_t
{
public:
template <typename F>
void register_function(const string& name, F&& fun)
{
m[name] = function(forward<F>(fun));
}
template <typename... A>
void call(const string& name, A&&... args)
{
auto it = m.find(name);
if (it == m.end())
throw logic_error(name + " not found");
else
any_cast<function<void(A...)>>(it->second)(forward<A>(args)...);
}
private:
map<string, any> m;
};
int main()
{
server_t server;
server.register_function("Add", [](int a, int b) { cout << a + b << endl; });
server.register_function("Echo", [](string s) { cout << s << endl; });
try
{
server.call("Add", 1, 2);
server.call("Echo", string("Howdy!"));
server.call("Subtract", 2, 1); // will throw: wrong name
server.call("Add", 1, 2, 3); // will throw: wrong number of arguments
server.call("Add", 1, 2.3); // will throw: wrong argument type (double instead of int)
}
catch (const exception& e)
{
cout << e.what();
}
}
[EDIT]
"...if i want to register like this : server. Register(..., [](string s, string& t){ t=s; }). Then, a failure will occur."
call
is not able to infer the types of arguments that the stored function expects. If you don't pass the exact types it expects, any_cast
will fail - which is better than crashing the application. The following should work:
//...
server.register_function("Put", [](const string& s, string& d) { d = s; });
try
{
const string s = "abc";
string d;
server.call("Put", s, d);
server.call<const string&, string&>("Put", "xyz", d);
//...