和其他人一样,如果可以避免,我建议您不要重新发明轮子。也就是说,如果可以,请使用现有框架。但我将稍微扩展一下可能的解决方案。
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() 的类的实例,该operator() 接受一个参数序列并对要调用的确切函数执行类型擦除。那很简单!至少如果你忽略细节的话。
参数的实现并不太复杂,您可以使用boost::any 并希望获得最好的结果,或者您可以使用更多信息实现自己的类型擦除,以便您可以执行更好的错误检测或隐式转换或...你的名字。
function_t 类型的实现有点复杂。我们需要在可调用的实际元素上执行类型擦除,std::function<> 适合这里的问题。但是我们不能使用它,因为这会给我们留下最小的函数接口:operator()你知道参数,而我们拥有的是operator()谁知道参数?
这是完成大部分工作的地方,如果您需要手动擦除类型。这可以通过提供virtual operator()( std::vector<parameter_t> [const] & ) [const] 的基本抽象类function_base 来实现(玩const-ness 或暂时忘记它以简化问题)。 function_t 将只保存指向该基类型的指针,并执行调用。到这里还是很简单的。
为函数实现类型擦除...现在下一个问题是如何实现来自function_base 的每个具体派生类型,而且事情变得有点棘手(我们同意其余的很简单,但没有我们?)您需要在function_t 中提供一个构造函数模板,它将采用any 函数,实例化从function_base 派生的模板类型并将指针存储在function_t 中。
再次为避免复杂性,假设您可以使用单个参数。剩下的只是更多的代码......function_impl<> 的实现只需要存储原始函数指针,并记住参数的类型和数量(在本例中为 1)。 operator() 的实现会迭代参数向量,并且对于每个参数,它都会取消擦除类型(转换回原始类型)并调用函数。这段代码在模板中几乎必须是手动的,但它可以被相同数量的所有函数重用。
为了让事情变得更简单,您可以使用函数特征库,它能够从您收到的函数中提取参数的类型和数量。
那么用户代码还剩下什么?这很简单,在这种情况下,我是认真的。你的接口应该提供function_t,它可以由any函数指针构造(只要它符合你在那里实现的要求),以及一个注册任何这样的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 推导,手动处理参数向量并调用该函数...如果您想在脚本语言中实现的操作很少,则可能不值得付出额外的努力使其具有通用性。