4

将业务逻辑功能实现为宏是一个好主意吗?

我继承了一些遗留的 C++ 代码,我发现很多业务逻辑功能都是用长而神秘的宏来实现的。

宏比函数有优势吗?使用宏的一般原理是什么?

哪种逻辑最适合宏?

这是代码中的一个简单示例

#define INSERT_VALUES(IN,ID,EO)     {\
    double evaluationOutput = EO;\
    int controls = 0;\
    int input_controls = m_input_controls[IN];\
    if(m_value_list[IN].ShouldProcess())\
        {\
        evaluationOutput = m_evaluationOutput[IN];\
        controls = m_controls[IN];\
        }\
    VALUE_EXIST(evaluationOutput,controls,input_controls,IN,ID,Adj);\
    m_evaluationOutput[IN] = controls > 0 ? evaluationOutput : 0.0;\
    m_controls[IN] = controls;\
    m_input_controls[IN] = input_controls;\                                 
}
4

3 回答 3

9

Effective C++中,Scott Meyers 在第 2 项中指出:

更喜欢consts, enums, 和inlines#defines

Meyers 特别提到了编写宏而不是函数的做法,他说:

该指令的另一个常见(错误)用法#define是使用它来实现看起来像函数但不会产生函数调用开销的宏。

像这样的宏有很多缺点,光是想想就很痛苦。

幸运的是,您不必忍受这种废话。通过使用内联函数的模板,您可以获得宏的所有效率以及常规函数的所有可预测行为和类型安全性。

【真正的功能】遵守范围和访问规则。例如,谈论一个类私有的内联函数是非常有意义的。一般来说,没有办法用宏来做到这一点。

具体回答您的问题:

  • 一些程序员编写宏而不是函数来避免函数调用的感知开销——这种可疑的做法通常没有什么可衡量的好处。
  • 程序员过去常常使用预处理器来生成样板代码(也许现在仍然如此)。在现代 C++ 中,处理器的使用应仅限于#include和(可能)#ifdef/#ifndef用于条件编译。

正如迈耶斯在结束时指出的那样:

现在还不是退役预处理器的时候,但你绝对应该给它长时间和频繁的假期。

于 2013-04-30T18:28:57.963 回答
6

不,它们绝对不是功能的一般替代品。

宏具有代码本身所不具备的功能,特别是在编译之前创建和修改标记(代码)。

作为交换,它们失去了所有类型安全性,以及几乎所有可用于实际代码的语法糖。

当您必须做一些代码无法完成的事情时,或者需要有条件地存在代码(超级调试的东西,如内存跟踪)时,宏就派上用场了。#define SUCCESS(x) (x >= 0)它们在提供更简洁或更易读的方式来做特定事情方面也有一定的价值(一个常见的例子是mutate at compile-time,它们几乎是不合适的。大多数看起来可能是宏的代码可能可以更安全地在实际代码中表达,这对业务逻辑很重要。

您可以获得的最接近的经验法则是在编译期间是否需要发生或更改某些事情。如果是这样,请考虑使用宏,否则只需对其进行编码。请记住,模板算作代码,可以做很多你可能会想用宏来做的事情,但可以更安全一些。

于 2013-04-30T17:46:58.787 回答
2

长的,神秘的东西都不好。如果存在性能问题的宏,您可以使用内联函数实现相同的结果。如果它们用于简化表达式,则可以将它们重构为不那么神秘并且更容易维护,如果您有时间和金钱进行这样的努力。

于 2013-04-30T18:00:11.210 回答