2022年6月21日 星期二

Macro 進階用法 - X Macro


C/C++ 語言常使用 Macro 來預先定義一些常常用到的值或程式碼片段,讓整體的
程式看起來更簡潔。

X Macro是種 Macro更進階的使用「方法」,而不是另一種「功能」。所以只要有
支援定義 Macro功能的程式語言,也可以使用。

其透過 "#define"與 "#undef"來替換 "X"的定義可以達到各種神奇的效果。

以下是一種最簡單範例:

#include <stdio.h>

#define LIST_OF_NAMES \
  X(Alice) \
  X(Bob) \
  X(Charlie) \
  X(Dan) \
  X(Emily)

int main() {
#define X(name) printf ("Hello %s\n", #name);
  LIST_OF_NAMES
#undef X
  return 0;
}


Output:

Hello Alice
Hello Bob
Hello Charlie
Hello Dan
Hello Emily

我在 LIST_OF_NAMES宣告由 "X()"組成的函數,這時的 "X"還沒有被定義。
在 "main()"中,才把 "X()"定義成使用 printf函數印出 name參數並呼叫
LIST_OF_NAMES。

如果將 LIST_OF_NAMES的 X Macro展開來寫,就會是這個樣子:

#include <stdio.h>

#define LIST_OF_NAMES \
  printf ("Hello %s\n", Alice); \
  printf ("Hello %s\n", Bob); \
  printf ("Hello %s\n", Charlie); \
  printf ("Hello %s\n", Dan); \
  printf ("Hello %s\n", Emily);

int main() {
  LIST_OF_NAMES
  return 0;
}

而 X Macro最妙的用法還在於可以替換"X"的定義,使其重複利用:

#include <stdio.h>

#define LIST_OF_NAMES \
  X(Alice) \
  X(Bob) \
  X(Charlie) \
  X(Dan) \
  X(Emily)

int main() {
#define X(name) printf ("Hello %s\n", #name);
  LIST_OF_NAMES
#undef X

#define X(name) printf ("Hi, I am %s\n", #name);
  LIST_OF_NAMES
#undef X
  return 0;
}

Output:

Hello Alice
Hello Bob
Hello Charlie
Hello Dan
Hello Emily
Hi, I am Alice
Hi, I am Bob
Hi, I am Charlie
Hi, I am Dan
Hi, I am Emily