制作库时是否应避免使用宏

Should MACROs be avoided when making a library

本文关键字:是否      更新时间:2023-10-16

库提供了一个派生类,并将派生类作为模板参数。

例:

class userclass : public lib::superclass<userclass>
{}

如您所见,要键入的内容很多。并且"用户类"应始终派生为公共类,以便其正常工作。所以我想出了两个看起来像这样的宏:

#define SUPER(x) public lib::superclass<x>
#define SUPERCLASS(x) class x : public lib::superclass<x>

用户现在可以键入其中之一。

class userclass : SUPER(userclass)
{}
SUPERCLASS(userclass)
{}

但主要问题是宏 SUPER 和 SUPERCLASS 存在于用户全局命名空间中的速度与包含标头一样快。

我可以/应该:

  1. 有办法保留命名空间要求但仍默认为公共派生?
  2. 按原样使用宏。
  3. 只需要求用户写出完整的"public lib::superclass"。

我使用的是 vs 11,该库针对的是 Windows 开发人员。

使用宏的第一条规则是"不要,如果有任何其他解决方案"。在这种情况下,还有另一种解决方案,因此请摆脱它们。

其次,你的宏弊大于利,因为人们不知道他们通过阅读它扩展到什么,而完整的定义却知道。说真的,您正在节省真正微小的字符数,而可读性却付出了可怕的代价。简单地写出继承要好得多。

这真的不是很多输入。我见过很多不应该缩短的更长的行。用宏隐藏它只会混淆你的代码。如果我快速浏览一下您的SUPERCLASS(userclass) {},我几乎可以猜到它是一个类(我不喜欢使用基于猜测的库),但我不知道它或其父级是否被称为userclass(或两者都不是)或它正在使用哪种继承。这意味着你必须记录它,并强迫人们在需要时查找它。

所以正确答案是选项 3 - 不要使用宏。

如果您确实确实需要在库中使用宏,请为其提供特定于库的前缀。这与您将到达命名空间宏一样接近。

我投票给3。只需要求用户写出完整的"public lib::superclass"。

在以下情况下,库中的宏可能很有用:

  • 真的有很多东西要写,
  • 有些东西必须写好几遍
  • 或者你想隐藏一个丑陋的实现细节,而语言不允许你这样做。

但在您的情况下:

  • 没有那么多可写,
  • 是的,您必须将类名输入两次,
  • 你不想隐瞒你正在子类的事实,甚至你正在写一个类!

我不认为类名的重复 - 一个积极的点 - 是值得的。特别是因为您将隐藏class关键字并给读者带来相当大的混乱。

无论如何,如果库使用宏,则习惯上将库名称放在所有宏的前面:

#define MY_FANCY_LIBRARY_NAME_SUPER(x) public lib::superclass<x>

但是现在你没有节省这么多打字...

PS:记住编程的黄金法则:

代码只写一次,但永远读,因此它应该很容易阅读,而不是容易编写。