什么时候宏可以使代码比函数更漂亮?
确切地说,编程语言不需要宏。 例如,没有宏,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
的枚举,其成员为one
, five
, ten
, fifteen
和thirty
。 那你就是这样做的:
-
首先创建一个名为
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_string
和to_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 }