【问题标题】:Metaprogramming C/C++ using the preprocessor使用预处理器对 C/C++ 进行元编程
【发布时间】:2012-05-25 05:17:38
【问题描述】:

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

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

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

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

现在,如果我要用高级语言编写代码,我会使用 lambda 字典来简化它。

我突然想到我可以使用宏将其简化为类似

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

case_call 是一个宏,可以将此代码扩展为第一个代码 sn-p。

但是,我对这是否被认为是好的风格持怀疑态度。我的意思是,它会减少打字工作并提高代码的干性,但它确实似乎在某种程度上滥用了宏系统。

你会走那条路,还是把整件事都打出来?您这样做的理由是什么?

编辑

一些澄清:

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

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

【问题讨论】:

  • 为什么要关闭投票 - 这是一个非常好的、有效的问题。我在这里错过了什么?
  • 这是一个很好的问题,但是“这个问题不适合我们的问答形式。我们希望答案通常涉及事实、参考资料或特定专业知识;这个问题可能会征求意见、辩论、争论、投票或扩展讨论。"
  • 在 C++ 11 中,您可以使用 lambda 字典来简化此操作。
  • 我不会回避宏,我认为 boost 可能在预处理器库中有你需要的东西,但我还没有使用过
  • 你能举一个更具体的例子来说明你现在拥有什么吗?

标签: c++ c coding-style macros metaprogramming


【解决方案1】:

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

一般的智慧是使用表格将键映射到操作:

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(...);

但是,如果如您所说,函数没有共同的签名(即,您不能使用成员函数指针),那么您实际上 应该 做什么取决于您的项目的具体情况,即我不知道。可能是宏是消除您看到的重复的唯一方法,也可能是有更好的方法来解决它。

问问自己:为什么我的函数采用不同的参数? 为什么我要使用演员表?如果您要根据对象的类型进行分派,则可能需要引入一个通用接口。

【讨论】:

  • "do_something 可以有不同的调用,所以我不能只使用函数指针。" void(Class::*)()。有些可能需要参数。至少我是这么理解的。
  • 实际上,我有两种不同的调用,所以如果我使用两个地图,这实际上会起作用。
【解决方案2】:

我建议你稍微调换一下角色。您是说该对象已经是某个知道如何处理某种情况的类,因此在您的基类中添加一个 virtual void handle(const char * key) 并让该对象在实现中检查它是否适用于它并执行任何必要的操作。

这不仅会消除冗长的 if-else-if 链,而且还会更安全,并让您在处理这些事件时更加灵活。

【讨论】:

  • 这并没有消除长 if-else-if 链,它只是移动/重新排列它。但是,这仍然是一个非常好的主意。
  • @MooingDuck 它不会消除个别的 ifs,但会消除必须处理的中心、长长的案例列表。每个检查都将在实际处理发生的类中,因此必须更改以添加新功能的位置将靠近。
  • 这是一个有趣的想法。这将需要我修改实现类,由于各种原因,目前不希望这样做,但这当然是个好主意。
  • 实际上,我可以在一个独立的函数中实现决策树,根据子类类型有几个特化。有趣的想法...
猜你喜欢
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多