bas*_*ibe 13 c c++ macros coding-style metaprogramming
所以我有这个巨大的树,基本上是一个大的开关/案例,带有字符串键和一个公共对象上的不同函数调用,具体取决于键和一个元数据.
每个条目基本上都是这样的
} else if ( strcmp(key, "key_string") == 0) {
((class_name*)object)->do_something();
} else if ( ...
Run Code Online (Sandbox Code Playgroud)
哪里do_something可以有不同的调用,所以我不能只使用函数指针.此外,某些键需要将对象强制转换为子类.
现在,如果我用更高级别的语言编写代码,我会使用lambdas字典来简化这一过程.
在我看来,我可以使用宏来简化这类
case_call("key_string", class_name, do_something());
case_call( /* ... */ )
Run Code Online (Sandbox Code Playgroud)
哪个case_call是将此代码扩展到第一个代码段的宏.
然而,我非常关注这是否会被视为好风格.我的意思是,它会减少打字工作并改善代码的干燥度,但它确实似乎在某种程度上滥用了宏系统.
你会走那条路,还是整理出整条路?你这样做的原因是什么?
编辑
一些澄清:
此代码用作简化脚本API之间的粘合层,该API作为简单的键值属性访问C++ API的几个不同方面.这些属性在C++中以不同的方式实现:有些具有getter/setter方法,有些是在特殊结构中设置的.脚本操作引用C++对象转换为公共基类.但是,某些操作仅适用于某些子类,必须进行转换.
接下来,我可能会更改实际的C++ API,但目前,它必须被视为不可更改.此外,这必须在嵌入式编译器上工作,因此(遗憾的是)boost或C++ 11不可用.
在我看来,适当使用宏.毕竟,它们是为了避免语法重复而制作的.然而,当你有语法重复时,它并不总是语言的错误 - 可能有更好的设计选择可以让你完全避免这个决定.
一般的智慧是使用表映射键来执行操作:
std::map<std::string, void(Class::*)()> table;
Run Code Online (Sandbox Code Playgroud)
然后查找并一次调用该操作:
object->*table[key]();
Run Code Online (Sandbox Code Playgroud)
或者用于find检查失败:
const auto i = table.find(key);
if (i != table.end())
object->*(i->second)();
else
throw std::runtime_error(...);
Run Code Online (Sandbox Code Playgroud)
但是如果你说没有函数的共同签名(即你不能使用成员函数指针)那么你实际上应该做什么取决于你不知道的项目细节.可能是一个宏是唯一可以忽略你所看到的重复的方法,或者可能是一个更好的方法来实现它.
问问自己:为什么我的函数采用不同的论点?我为什么要使用演员表?如果您要调度对象的类型,则可能需要引入通用接口.
我建议你稍微改变角色.你说这个对象已经是一个知道如何处理某种情况的类了,所以virtual void handle(const char * key)在你的基类中添加一个,让对象检查实现是否适用于它并做任何必要的事情.
这不仅可以消除长if-else-if链,而且还可以更安全,并且可以更灵活地处理这些事件.