0

我希望允许从有点像脚本的文本文件中调用我的程序中的函数。

我希望能够使用此“脚本管理器”注册任何功能,而无需强制它符合某些特定签名。因此能够从脚本调用:MyFunc(bool, string) 或 MyFunc2(int, float, char)。在解析方面,我可以将这些参数放入参数列表中,但问题是如何将这些参数传递给函数?

我不能像 MyFunc(paramlist[0], paramlist[1]) 那样称呼它,因为这会强制执行特定的签名。我也不希望被调用的函数需要了解“脚本管理器”,因此它们不需要能够处理参数列表。

如何在不围绕前者(被调用的函数)编写一些包装器的情况下解耦这两个组件(被调用的函数和“脚本管理器”)?

4

2 回答 2

0

Of course you can do stuff like that yourself, but I think that it is better just to use Lua (http://lua.org ). Lua integrates greatly with c/c++ programs and there is a lot of comprehensive documentation and tutorials available; for example, have a look at this one: http://csl.sublevel3.org/lua/ (pay attention to the section "calling C functions from Lua", this is what you want).

于 2011-07-22T05:38:49.760 回答
0

与其他人一样,如果可以避免,我建议您不要重新发明轮子。也就是说,如果可以,请使用现有框架。但我将稍微扩展一下可能的解决方案。

C++ 没有反射,这意味着您不能在运行时接受函数指针、检查它并解释参数是什么。但是你可以在编译时这样做。解决方案并不简单,但可以通过类型擦除来完成。为了简化问题,我假设所有函数返回void它都足够复杂。

在一种潜在的解决方案中,调度程序结构可能看起来像(忽略错误):

while (true) {
   std::string func = read_function_name();
   std::vector<parameter_t> params = read_parameters();
   functions[ func ]( params );
}

现在来填补空白:read_function_name是一个简单的函数,它返回要调用的函数的名称。不是功能,只是名称。read_parameters是一个处理输入文件并构建要传递给函数的参数序列的函数。functions是一个关联容器,将函数名称映射到我们的一个函数。参数是实际参数类型的某种类型擦除,因此我们可以在单个容器中通用地管理它们。我们的函数是一个类的实例,它实现了一个operator()接受一个参数序列并对要调用的确切函数执行类型擦除的类。那很简单!至少如果你忽略细节。

参数的实现并不太复杂,您可以只使用boost::any并希望最好,或者您可以使用更多信息实现自己的类型擦除,以便您可以执行更好的错误检测,或隐式转换或...... .

类型的实现function_t有点复杂。我们需要对可调用的实际元素执行类型擦除,并将std::function<>问题解决到这里。但是我们不能使用它,因为这会给我们留下最小的函数接口:operator() 你知道参数,而我们所拥有的是operator() 谁知道参数

这是大部分工作要做的地方,如果您需要手动擦除类型。这可以通过function_base提供一个virtual operator()( std::vector<parameter_t> [const] & ) [const](玩 const-ness 或暂时忘记它以简化问题)的基本抽象类来实现。将function_t只保存一个指向该基类型的指针,并执行调用。到这里还是很简单的。

实现函数的类型擦除......现在下一个问题是如何实现每个具体派生类型 from function_base,并且事情变得有点棘手(我们同意其余的很简单,不是吗?)你需要提供一个构造函数模板function_t,它将接受任何函数,实例化一个派生自的模板类型function_base并将指针存储在function_t.

再次为避免复杂性,假设您可以使用单个参数。剩下的只是更多的代码...... 的实现function_impl<>只需要存储原始函数指针,并记住参数的类型和数量(在本例中为 1)。的实现operator()迭代参数向量,并为每个参数取消类型(转换回原始类型)并调用函数。这段代码在模板中几乎必须是手动的,但它可以用于相同数量的所有功能。

为了让事情在这里变得更简单,您可以使用函数特征库,它将能够从您收到的函数中提取参数的类型和数量。

那么用户代码还剩下什么?这很简单,在这种情况下,我是认真的。你的接口应该提供function_t,它可以由任何函数指针构造(只要它符合你在那里实现的要求),以及一个function_t通过提供名称在你的系统中注册任何此类的函数:

// user code: registration of a new function
void print_single_int( int );
lib::function_t f( &print_single_int );
lib::register( "print_single_int", f );

必须为要添加到系统的每个功能键入这两行。当然,您可能会决定解决方案的复杂性并不能弥补问题并进行手动实现,如果用户代码只是创建手动编码的推导function_base,手动处理参数向量并调用函数......如果有您想在脚本语言中实现的操作很少,因此使其通用化可能不值得付出额外的努力。

于 2011-07-22T08:11:10.063 回答