宏什么时候能让代码比函数更漂亮
When could macro make code more beautiful than function does?
确切地说,编程语言不需要宏。例如,Java在没有宏的情况下工作得很好。通常宏会使代码更清晰、更短,同时也更危险。
那么,使用宏的最佳方式是什么呢?让我们用代码说话。
使用宏,您可以为以下问题编写一个漂亮的解决方案:
- 定义枚举,使其值可以转换为字符串表示形式,反之亦然
假设要定义一个名为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 <string> //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 "<error>";
}
现在,你可以这样写:
#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
将正常工作,无需任何修改!
--
我把这个解决方案从我的解决方案中带到了另一个问题,发布在这里:
- 从enum转换为int
我认为最好的方法是使用inline
您可以获得宏+所有编译时检查的所有好处
宏在c++中的主要作用是控制编译。类似于:
#ifdef DEBUG:
//print some debug information
#endif
或
#ifdef OS_WINDOWS
//windows specific code
#
我只在其他地方使用宏。
一个例子是从错误值到字符串的简单映射,例如代替
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 120n"
"..."
GLSL_UNROLL_FOR("int i",0,10,
"foo += in"
)
"...";
在我个人看来,一个好的宏是非常罕见的。我尽量避开它们,因为它们中的大多数更像一颗定时炸弹。
要想做得好,宏必须:
- 简单一点
- 永远不要模棱两可
- 永远不要破坏代码结构(我见过像
#define MACRO } someCode {
这样的宏,这很糟糕) - 不能抛出异常或类似的东西,基本上,它决不能让调试变得更困难
- 有一个能清楚解释意思的名字
- 必须有充分的理由使用宏,而不是内联函数,如编译控制或标头保护
这里有一个示例(易于维护)。
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
}
相关文章:
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 如何使用gdb制作一个可以漂亮地打印每个对象的C++函数
- 宏什么时候能让代码比函数更漂亮
- 如何从 dbx 的漂亮打印函数调用 dbx 自己的打印函数
- 如何在gdb中为漂亮的打印机调用构造函数
- 使用模板检查结构体中的字段,启用函数if,并在失败时给出一个漂亮的错误消息