什么时候宏可以使代码比函数更漂亮?

确切地说,编程语言不需要宏。 例如,没有宏,Java工作得很好。 通常,宏使代码更清晰,更短,同时更危险。

那么,使用宏的最佳方法是什么? 我们在代码中谈谈。

我只在没有其他function的地方使用宏。

一个例子是从错误值到字符串的简单映射,例如代替

switch(code) { case ERR_OK: return "ERR_OK"; case ERR_FOO: return "ERR_FOO"; : 

我使用一个简单的宏

 #define CASE_STR(x) case x: return #x 

所以我可以简化这个

 switch(code) { CASE_STR(ERR_OK); CASE_STR(ERR_FOO); : 

但是,这些情况通常更多用于调试。

另外,我编写了一个GLSL(OpenGL着色语言)循环,使用boost预处理器套件展开一次,然后可以使用类似的东西

 const char *shader = "#version 120\n" "..." GLSL_UNROLL_FOR("int i",0,10,\ "foo += i\n" \ ) "..."; 

使用宏,您可以为问题编写一个漂亮的解决方案,例如:

  • 定义一个枚举,使其值可以转换为字符串表示forms,反之亦然。

假设,您要定义一个名为period的枚举,其成员为onefivetenfifteenthirty 。 那你就是这样做的:

  • 首先创建一个名为period_items.h的头文件:

     //period_items.h //Here goes the items of the enum //it is not a definition in itself! E(one) E(five) E(ten) E(fifteen) E(thirty) 
  • 然后创建另一个名为period.h头文件:

     //period.h #include  //HERE goes the enum definition! enum period { #define E(item) item, #include "period_items.h" //it dumps the enum items in here! #undef E period_end }; period to_period(std::string const & name) { #define E(item) if(name == #item) return item; #include "period_items.h" #undef E return period_end; } 

现在你可以简单地包含period.h并使用to_period函数。 🙂

您还可以将此函数添加到period.h中:

 std::string to_string(period value) { #define E(item) if(value == item) return #item; #include "period_items.h" #undef E return ""; } 

现在,你可以这样写:

 #include "period.h" period v = to_period("fifteen"); //string to period std::string s = to_string(v); //period to string 

为什么这个解决方案很漂亮

因为现在如果你想在枚举中添加更多的成员,你所要做的就是将它们添加到period_items.h中:

  //period_items.h //Here goes the items of the enum //it is not a definition in itself! E(one) E(five) E(ten) E(fifteen) E(thirty) E(fifty) //added item! E(hundred) //added item! E(thousand) //added item! 

而且你已经完成了。 to_stringto_period可以正常工作,无需任何修改!

我从我的解决方案中解决了另一个问题,发布在这里:

  • 从枚举转换为int

我认为最好的方法是使用inline

您可以获得宏+所有编译时间检查的所有好处

在c ++中有用的主要function是控制编译。 就像是:

 #ifdef DEBUG: //print some debug information #endif 

要么

 #ifdef OS_WINDOWS //windows specific code # 

在我个人看来,一个好的宏是一件非常罕见的事情。 我试图尽可能地避免它们,因为它们中的大多数更像是定时炸弹。

为了好,宏必须:

  • 简单。
  • 永远不要暧昧
  • 永远不要制造代码结构(我见过像#define MACRO } someCode {这样的#define MACRO } someCode { ,这很糟糕)
  • 无法抛出exception,或类似的东西,基本上,它绝不能让调试更难
  • 有一个名称可以清楚地解释其含义
  • 必须有一个非常好的理由使用宏而不是内联函数,比如编译控制或标题保护。

这是一个例子(可轻松维护)。

 enum id { #define ITEM(id, s) id, # include "foo.itm" #undef ITEM nbItem }; static char const *const s[] = { #define ITEM(id, s) s, # include "foo.itm #undef ITEM }