繁体   English   中英

使用预处理器对C / C ++进行元编程

[英]Metaprogramming C/C++ using the preprocessor

所以我有这个巨大的树,基本上是一个大的开关/案例,带有字符串键和一个公共对象上的不同函数调用,具体取决于键和一个元数据。

每个条目基本上都是这样的

} else if ( strcmp(key, "key_string") == 0) {
    ((class_name*)object)->do_something();
} else if ( ...

do_something可以有不同的调用,所以我不能只使用函数指针。 此外,某些键需要将对象强制转换为子类。

现在,如果我用更高级别的语言编写代码,我会使用lambdas字典来简化这一过程。

在我看来,我可以使用宏来简化这类

case_call("key_string", class_name, do_something());
case_call( /* ... */ )

其中case_call是一个宏,可以将此代码扩展到第一个代码片段。

然而,我非常关注这是否会被视为好风格。 我的意思是,它会减少打字工作并改善代码的干燥度,但它确实似乎在某种程度上滥用了宏系统。

你会走那条路,还是整理出整条路? 你这样做的原因是什么?

编辑

一些澄清:

此代码用作简化脚本API之间的粘合层,该API作为简单的键值属性访问C ++ API的几个不同方面。 这些属性在C ++中以不同的方式实现:有些具有getter / setter方法,有些是在特殊结构中设置的。 脚本操作引用C ++对象转换为公共基类。 但是,某些操作仅适用于某些子类,必须进行转换。

接下来,我可能会更改实际的C ++ API,但目前,它必须被视为不可更改。 此外,这必须在嵌入式编译器上工作,因此(遗憾的是)boost或C ++ 11不可用。

在我看来,适当使用宏。 毕竟,它们是为了避免语法重复而制作的。 然而,当你有语法重复时,它并不总是语言的错误 - 可能有更好的设计选择可以让你完全避免这个决定。

一般的智慧是使用表映射键来执行操作:

std::map<std::string, void(Class::*)()> table;

然后查找并一次调用该操作:

object->*table[key]();

或使用find检查失败:

const auto i = table.find(key);
if (i != table.end())
    object->*(i->second)();
else
    throw std::runtime_error(...);

但是如果你说没有函数的共同签名(即你不能使用成员函数指针)那么你实际上该做什么取决于你不知道的项目细节。 可能是一个宏是唯一能够忽视你所看到的重复的方法,或者可能是一种更好的方式来实现它。

问问自己: 为什么我的函数采用不同的论点? 我为什么要使用演员表? 如果您要调度对象的类型,则可能需要引入通用接口。

我建议你稍微改变角色。 你说这个对象已经是一个知道如何处理某种情况的类了,所以在你的基类中添加一个virtual void handle(const char * key) ,让对象检查实现是否适用于它并做什么是必要的。

这不仅可以消除长if-else-if链,而且还可以更安全,并且可以更灵活地处理这些事件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM