第一次看到X-macro這個技術時,是在[C/C++] enum to string 的方法實作 (X Macro)這篇文章中,
當時看得「霧霧煞煞」(台語:一頭霧水之意),但由於是滿有趣的技巧,
所以就先將其存在evernote中了。
昨天為了寫個功能,想做類似的事
所以特別打開evernote中的記事來研究一下,
終於看懂這個東西了,
所以在這邊記錄一下我對X-Macro的理解!
第一次看到X-Macro時,總是無法將三個小巨集(Macro)連起來,
看懂後發現是我想的太複雜了
先來個例子:
一般而言,將enum轉成字串,可能會用下面的方式
#include <iostream>
enum eOption
{
option1,
option2,
option3
};
char* OptStr[] = {"option1", "option2", "option3" };
const char* enum2str(eOption idx)
{
return OptStr[idx];
}
int main(int argc, char* argv[])
{
printf("%s\n", enum2str(eOption::option1));
printf("%s\n", enum2str(eOption::option2));
printf("%s\n", enum2str(eOption::option3));
system("pause");
return 1;
}
若用X Macro寫,則是
// Here using X Macro
#include <iostream>
// define TABLE
#define TABLE \
SUBSTITUTED(option1, "option1") \
SUBSTITUTED(option2, "option2") \
SUBSTITUTED(option3, "option3")
// using TABLE to generate enum
#define SUBSTITUTED(a, b) a,
enum eOption
{
TABLE
};
#undef SUBSTITUTED
// using TABLE to generate string array
#define SUBSTITUTED(a, b) b,
char* OptStr[] = {TABLE};
#undef SUBSTITUTED
const char* enum2str(eOption idx)
{
return OptStr[idx];
}
int main(int argc, char* argv[])
{
printf("%s\n", enum2str(eOption::option1));
printf("%s\n", enum2str(eOption::option2));
printf("%s\n", enum2str(eOption::option3));
system("pause");
return 1;
}
看起來複雜,但其實很簡單
這裡分兩個部分:
定義用的巨集
使用時的巨集
以及
定義的巨集比較沒問題,
就只是很簡單的定義
「 『SUBSTITUTED(option1, "option1") SUBSTITUTED(option2, "option2") SUBSTITUTED(option3, "option3")』就是『TABLE』」,
比較有問題的應該是使用的時候。
其實使用的時候,是定義一個巨集,
將前一個巨集的SUBSTITUTED(option1, "option1")替換掉,
以宣告enum為例,就是用輸入的「a」加上逗號(也就是「a,」)來替換掉SUBSTITUTED;
第二個部分就是使用輸入的「b」加上逗號(也就是「b,」)來替換掉SUBSTITUTED。
至於#undef,就是為了將巨集的使用限制在某個小小的區域而已。
其實使用X Macro寫及不使用X Macro是一樣的,
差別只是可以集中修改。
當專案龐大時,若未使用X Macro,
就要一次修改兩份檔案,一直切換頗麻煩的,而且容易出錯;
若使用 X Macro,就只需要在一個檔案中修改,
省去切換的麻煩。
X Macro還可以用來做很多事,
在參考資料[3]中,就用來存函式指標的陣列,
還有趣的!
X Macro在C語言及C++ 11以前的編譯器中,
用處滿廣的,可用來做mapping table,
但C++ 11後,有std::map,
其作用就相對小很多。
不還一點,就是使用X Macro會使可讀性就會稍微降低些,
除非有一定熟悉程度的人來維護,
不然會有點麻煩。
程式碼已上傳git(這裡),
有興趣的可以去看看
雖然研究完,發現跟我想做的事還是有點小差距,
我想做的是執行時期的mapping,
而x macro是編譯時期的mapping(就跟巨集一樣),
看來我還是只能乖乖使用class來實現!
參考資料:
[2] X Macro ─ Wiki
這封郵件來自 Evernote。Evernote 是您專屬的工作空間,免費下載 Evernote |
沒有留言:
張貼留言