我有一个包含许多命令行选项的代码库.目前,如果在命令行上传入命令,则每个命令行选项都与表中的函数指针一起存在于表中.
例如
static CommandFunction s_Commands[] =
{
{ "command1", Func1 },
{ "command2", Func2 },
{ "command3", Func3 },
etc...
};
Run Code Online (Sandbox Code Playgroud)
我的问题是,表格很大,而且功能在其他地方.我更喜欢命令的字符串住在每个函数旁边.
例如:
COMMAND_ARG("command1")
void Func1()
{
dostuff
...
}
COMMAND_ARG("command2")
void Func2()
{
dostuff
...
}
COMMAND_ARG("command3")
void Func3()
{
dostuff
...
}
Run Code Online (Sandbox Code Playgroud)
这可能吗?
您可以使用由函数地址专门设计的模板来执行此操作:
#include <stdio.h>
// In a header file.
template<void(*Fn)()>
struct FnMeta
{
static char const* const meta;
};
// no definition of meta
// some.cc
void some() {}
template<> char const* const FnMeta<some>::meta = "some";
// another.cc
void another() {}
template<> char const* const FnMeta<another>::meta = "another";
// main.cc
int main() {
printf("%s\n", FnMeta<some>::meta);
printf("%s\n", FnMeta<another>::meta);
}
Run Code Online (Sandbox Code Playgroud)
上面的想法FnMeta<>::meta
是没有定义的.但是,不同的翻译单元(.cc文件)可以提供专业化的定义FnMeta<>::meta
.这种方式在FnMeta<X>::meta
使用时链接器在另一个转换单元中找到它的适当定义.
这个特定问题有不同的方法.您可以使用继承,通过继承创建基础Command
然后实现某些execute
功能(您也可以实现help
,validate
....).然后创建一个调度程序函数,将函数名称与命令的实际实现相关联(在各种查找表中,可能是a map
).
虽然这不能解决您的地方问题,但这个问题可能是真实的.也就是说,命令的实现可能到处都是,但是有一个地方可以确定CLI中可用的命令.
如果locality对您来说非常重要(代价是在源代码中没有一个位置,其中列出了所有使用的命令),您可以提供全局可访问的注册机制,然后提供一个帮助器类型,施工将把功能登记到机制中.然后,您可以使用每个函数定义创建一个此类对象.
CommandRegistry& getCommandRegistry(); // Access the registry
struct CommandRegister {
CommandRegister(const char* name, Function f) {
getCommandRegistry().registerCmd(name,f);
}
// Optionally add deregistration
};
// ...
void Func2() {...}
static CommandRegister Func2Registration("function2",&Func2);
Run Code Online (Sandbox Code Playgroud)
我个人更喜欢走另一条路...在代码中有一个单独的位置列出所有命令,因为它允许在一个位置找到执行它的代码的命令(文本).也就是说,当您有一些命令而其他人需要维护其中一个命令时,它会更容易从命令行转到执行它的实际代码.