C ++通过字符串名称调用不同的函数

时间:2013-12-18 10:07:36

标签: c++ visual-studio-2010 boost function-pointers

我对C ++比较陌生 - 我在6年多前就开始学习它,但直到几个月前才开始使用它。

场景是什么

  • 具有大量模块的相当大的系统。

所需输出

  • 模块(即X)“公开”某些要通过网络调用的函数,并将结果发送回调用者(即Y)
  • 调用者Y不知道有关X的任何信息,尽管库中公开了什么(函数名称和参数)。
  • 从库中调用X中的函数必须通过从Y接收的字符串或一组字符串来进行,因为还会有参数。

理想情况下,我想要的是具有变量返回/参数类型或某种类型擦除的尽可能通用的东西 - 因为我不知道每个模块将要公开哪些函数。我认为用C ++运行这样的东西是非常有意义的。但希望通过预先确定的可能返回/参数类型,这是可行的。通信现在不是问题,重要的是在模块方面应该做什么。

问题

  • 使用C ++和Boost可以实现这样的功能吗?如果有人可以给我一些指导 - 文学/教程/(伪)代码示例等等,我会非常感激。我不希望这里有完整的解决方案。

可能的解决方案:

我对可以/应该使用的语言的“功能”有点失落 - 主要是由于我在项目中的限制。

我考虑使用Variadic模板并发现下面的问题,这确实有帮助,唯一的问题是VS2010不支持Variadic模板。

Generic functor for functions with any argument list

经过网络上的一些广泛研究后,我得到的最接近的答案是:

map of pointers to functions of different return types and signatures

情景几乎相同。然而,在我看来,OP之前已经知道他将使用的函数的返回/参数。由于我的声誉很低(我刚加入),我很遗憾不能在那里询问/评论任何内容。

TBH我不太清楚如何完成所选答案的解释。

使用map是一种方法,但我必须存储包含函数指针的对象(也在问题中回答),但是由于可以在用户提供的代码中看到它,它确实有一些难点 - 编码我不想要的东西。

进一步澄清:

  • 是的,我只能使用C ++和VS2010 SP1。
  • 不,尽管Boost,我不能使用任何其他第三个图书馆 - 能够使用一些反思库如CPGF http://www.cpgf.org/会很棒(即使我不是100%肯定,如果这就是我真的需要)

次要编辑: - 脚本语言绑定(例如LUA)确实是一种方法,但我不想将它包含在项目中。

我希望有人可以解释这个问题!

提前感谢任何输入!

1 个答案:

答案 0 :(得分:2)

看起来你需要一个小反射模块。例如,我们有一个方法信息结构,例如:

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;
}

然后用所有导出函数编译一个dll

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; }
解释器代码中的

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); 
}

我希望它可以帮助你。