C++ 寻找最优雅的代码调度器

C++ 寻找最优雅的代码调度器,c++,c,design-patterns,coding-style,C++,C,Design Patterns,Coding Style,我认为这个问题很普遍。您有一些输入字符串,并且必须根据字符串的内容调用函数。类似于字符串的switch()。 考虑命令行选项 目前我正在使用: using std::string; void Myclass::dispatch(string cmd, string args) { if (cmd == "foo") cmd_foo(args); else if (cmd == "bar") cmd_bar(args); else if .

我认为这个问题很普遍。您有一些输入字符串,并且必须根据字符串的内容调用函数。类似于字符串的switch()。 考虑命令行选项

目前我正在使用:

using std::string;

void Myclass::dispatch(string cmd, string args) {
    if (cmd == "foo")
        cmd_foo(args);
    else if (cmd == "bar")
        cmd_bar(args);
    else if ...
        ...
    else
       cmd_default(args);
}

void Myclass::cmd_foo(string args) {
...
}

void Myclass::cmd_bar(string args) {
...
}
在标题中

class Myclass {
    void cmd_bar(string args);
    void cmd_foo(string args);
}
所以每一个foo和bar我都要重复四(4!)次。我知道我可以先将函数指针和字符串馈送到静态数组,然后在循环中进行调度,从而保存一些if…else行。但是,是否存在一些宏欺骗(或预处理器滥用,取决于POV),使得以某种方式定义函数并同时自动更新数组成为可能? 所以我只需要写两次,或者如果内联使用,可能只写一次


我正在寻找C或C++的解决方案。

< P>听起来好像你在寻找

大概是这样的:

创建一个像这样的地图

std::map<std::string, Command*> myMap;
您可以构建字符串->函数指针的哈希表

typedef void (*cmd)(string);

丑陋的宏解决方案,这是你想要的。请注意,它不会自动注册,但会使某些内容保持同步,如果只添加到映射,而不添加源文件中的函数,还会导致编译错误

A.h:

// Note: no fileguard
// The first is  the text string of the command, 
// the second is the function to be called, 
// the third is the description.
UGLY_SUCKER( "foo", cmd_foo, "Utilize foo." );
UGLY_SUCKER( "bar", cmd_bar, "Turn on bar." );
Parser.h:

class Myclass {
...
protected:
    // The command functions
    #define UGLY_SUCKER( a, b, c ) void b( args )
    #include Mappings.h
    #undef UGLY_SUCKER
};
Parser.cpp:

void Myclass::dispatch(string cmd, string args) {
    if (cmd == "")
        // handle empty case
#define UGLY_SUCKER( a, b, c ) else if (cmd == a) b( args )
#include Mappings.h
#undef UGLY_SUCKER
    else
       cmd_default(args);
}

void Myclass::printOptions() {
#define UGLY_SUCKER( a, b, c ) std::cout << a << \t << c << std::endl
#include Mappings.h
#undef UGLY_SUCKER
}

void Myclass::cmd_foo(string args) {
...
}
void Myclass::dispatch(字符串cmd,字符串args){
如果(cmd==“”)
//处理空箱
#如果(cmd==a)b(args),则定义(a,b,c)else
#包括映射
#丑陋的傻瓜
其他的
cmd_默认值(args);
}
void Myclass::printOptions(){

#定义(a,b,c)std::cout根据问题注释中的“我的链接”,基本解决方案是将字符串映射到某种函数调用

要实际注册字符串->函数指针/函子对,请执行以下操作:

首先,创建一个单例(震惊!恐怖!)调度程序对象。 让我们称之为Dispatcher——它是
地图的包装,其中
Func是函数指针或函子类型

然后,创建一个register类:

struct Register {
   Register( comst string & s, Func f ) {
      TheDispatcher.Add( s, f );
   }
};
现在在您创建的各个编译单元中 静态对象(震惊!恐怖!):

将创建这些对象(假设代码不在静态库中),并将自动向Dispatcher注册


在运行时,您可以在Dispatcher中查找字符串并执行关联的函数/functor。

您必须至少定义函数并将它们添加到某个注册表中。(如果它们是某个类的非内联成员函数,您还必须声明它们。)而不是生成实际代码的特定于域的语言(比如)我认为没有办法提及这两个(或三个)功能《泰晤士报》。

这个问题已经被反复问过了,我在这里回答了。他还要求某种注册计划,以减少维护词典的工作量。他是的,但我认为没有一个能让他满意。你可以用宏做一些粗糙和丑陋的事情,但这比它的价值更麻烦。不,这是问题我使用了一个名为“cmd_*的函数”但它们可能是不同的,不需要表示命令。另外,dispatcher不需要绑定在对象中。@drhirsch。它们不必是实际的命令。这只是模式的名称。基本上,这是一种基于输入执行一些预定义代码的方法。我认为Neil和Glen ar的解决方案E建议是正确的答案。它不包括自注册,但我不确定C++中有一种干净的方式。在爪哇或C,它是非常可行的。@ Steven You可能在每个命令类中使用某种形式的静态初始化进行自注册。尽管如此,您可能需要使您的STD::Map是一个单例。就像你说的,它不是很干净它不需要干净,请注意,我明确表示asekd用于预处理器滥用。但是这个解决方案看起来很有趣,它确实给了我一些新的想法。但是现在我需要CommandFoo和CommandBar类声明和构造函数,所以我再次重复Foo和Bar四次。当然,它是丑陋的,但是它似乎把重复减少到了两个。但是在代码中间包含一个非常丑陋的。+ 1 + 1,出于同样的原因。同样,假设每个命令“FoO”导致调用CMDYFO,有一点严格化,你也可以避免重复这些参数。是的,我在沿着“粘贴”的线条思考。运算符到。这不是模式的实际替代方案:它是相同的概念,不同的实现方式。是的,我想我终于明白了这一点。
void Myclass::dispatch(string cmd, string args) {
    if (cmd == "")
        // handle empty case
#define UGLY_SUCKER( a, b, c ) else if (cmd == a) b( args )
#include Mappings.h
#undef UGLY_SUCKER
    else
       cmd_default(args);
}

void Myclass::printOptions() {
#define UGLY_SUCKER( a, b, c ) std::cout << a << \t << c << std::endl
#include Mappings.h
#undef UGLY_SUCKER
}

void Myclass::cmd_foo(string args) {
...
}
struct Register {
   Register( comst string & s, Func f ) {
      TheDispatcher.Add( s, f );
   }
};
Register r1_( "hello", DoSayHello );