Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Calling different functions by string name

I am relatively new to C++ - I leanerd it some 6+ years ago, but have never really used it until some months ago.

What is the scenario:

  • Considerably large system with a lot of modules.

Desired Output:

  • Modules (namely X) "expose" certain functions to be called over network and have the result sent back to the caller (namely Y)
  • The caller Y doesn´t know any info about X, despite what was exposed by the library (function name and parameters).
  • The calling of function in X from the library will have to happen through a string received from Y - or a set of strings, as there will be parameters as well.

Ideally what I want to have is something as generic as possible with variable return/paramaters types, or some kind of type-erasure - owing to the fact that I don´t know which functions each module will want to expose. I reckon its quite utopic to get something like that running in C++. But hopefully with pre-determined possible return/parameter types, it is feasible. The communication is not a problem for now, what matters is what should be done in the module side.

Question:

  • Would it be possible to accomplish such thing using C++ and Boost ? I would be really greateful if someone could give me some guidelines - literature/tutorials/(pseudo)code examples and so on and so forth. I am ofc not expecting a full solution here.

Possible solution:

I am a little bit lost as to which "functionalities" of the languages I can/should use - mainly due to my restrictions in the project.

I thought about using Variadic Templates and found the question below, which really helps, the only problem is that Variadic Templates are not supported in VS2010.

Generic functor for functions with any argument list

After some extensive research in the Web, the closest answer I got was this:

map of pointers to functions of different return types and signatures

The scenario is pretty much the same. The difference, however, seems to me that the OP already knows beforehand the return/parameters the functions he will be using. Due to my low reputation (I just joined) I unfortunately cannot ask/comment anything there.

TBH I didn´t get that well how to accomplish what the selected answer explains.

Using maps is a way, but I would have to store objects which contains function pointers (as also answered in the question), but as it is possible to see in the provided code by the user, it does have some hard-coded stuff which I wasn´t desiring to have.

Further clarifications:

  • Yes, I am restricted to use C++ AND VS2010 SP1.
  • No, despite Boost, I cannot use any other 3rd library - it would be great to be able to use some Reflection libraries such as CPGF http://www.cpgf.org/ (even though I am not 100% sure if thats what I really need)

Minor Edit: - Scripting language bindings (such as LUA) are indeed a way to go, yet I didn´t want to include it in the project.

I hope someone can shed light on this problem!

Thanking in advance for any input!

like image 624
skullmetal Avatar asked Dec 18 '13 10:12

skullmetal


1 Answers

Looks like you're needed a little reflection module. For example we have a struct of method info such as:

struct argument_info {
    std::string name;
    std::string type;
    std::string value;
}

struct method_info {
    std::string method_name;
    std::string return_type;
    std::list<argument_info> arguments;
}

then compile a dll with all exported functions

extern"C" __declspec(dllexport) void f1(int a, int b){/*...*/}
extern"C" __declspec(dllexport) int f1(std::string a, int b, char* c){ return x; }

in the interpreter's code:

void call_function(method_info mi, argument_info& t_return)
{
    /* let g_mi be a map, where key is a std::string name of the method and the 
       value is method_info struct */ 
    if(!g_mi->find(mi.method_name))
        throw MethodNotFindException

    if(g_mi[mi.method_name].arguments.size() != mi.arguments.size())
        throw InvalidArgumentsCountException;

    for(int i = 0; i < g_mi[mi.method_name].arguments.size(); i++)
    {
        if(g_mi[mi.method_name].arguments[i].type != mi.arguments[i].type)
            throw InvalidArgumentException;
    }

    t_return = module->call(mi.arguments); 
}

I hope it may help you.

like image 147
Netherwire Avatar answered Sep 28 '22 02:09

Netherwire