西安達內培訓(http://www.xatarena.net)講師表示,C中的一個慣用方法,是說有一個已命名的實體列表,需要為它們中的每一個建立函數,將它們中的每一個初始化,并在不同的代碼模塊中擴展它們的名字。這在Mozilla的源碼中經常用到,我就是在那時學到這個技巧的。例如,在我去年夏天工作的那個項目中,我們有一個針對每個命令進行標記的宏列表。其工作方式如下:
#define FLAG_LIST(_)
_(InWorklist)
_(EmittedAtUses)
_(LoopInvariant)
_(Commutative)
_(Movable)
_(Lowered)
_(Guard)
它定義了一個FLAG_LIST宏,這個宏有一個參數稱之為 _ ,這個參數本身是一個宏,它能夠調用列表中的每個參數。舉一個實際使用的例子可能更能直觀地說明問題。假設我們定義了一個宏DEFINE_FLAG,如:
#define DEFINE_FLAG(flag) flag,
enum Flag {
None = 0,
FLAG_LIST(DEFINE_FLAG)
Total
};
#undef DEFINE_FLAG
對FLAG_LIST(DEFINE_FLAG)做擴展能夠得到如下代碼:
enum Flag {
None = 0,
DEFINE_FLAG(InWorklist)
DEFINE_FLAG(EmittedAtUses)
DEFINE_FLAG(LoopInvariant)
DEFINE_FLAG(Commutative)
DEFINE_FLAG(Movable)
DEFINE_FLAG(Lowered)
DEFINE_FLAG(Guard)
Total
};
接著,對每個參數都擴展DEFINE_FLAG宏,這樣我們就得到了enum如下:
enum Flag {
None = 0,
InWorklist,
EmittedAtUses,
LoopInvariant,
Commutative,
Movable,
Lowered,
Guard,
Total
};
接著,我們可能要定義一些訪問函數,這樣才能更好的使用flag列表:
#define FLAG_ACCESSOR(flag)
bool is##flag() const {
return hasFlags(1 << flag);
}
void set##flag() {
JS_ASSERT(!hasFlags(1 << flag));
setFlags(1 << flag);
}
void setNot##flag() {
JS_ASSERT(hasFlags(1 << flag));
removeFlags(1 << flag);
}
FLAG_LIST(FLAG_ACCESSOR)
#undef FLAG_ACCESSOR
一步步的展示其過程是非常有啟發性的,如果對它的使用還有不解,可以花一些時間在gcc –E上。 |
 |
|