“宏”這個玩意兒可能會觸動很多人抵觸的情緒,我也一樣:很討厭它。通常我不會用它進行計算,只有在合適的時候(比如能讓我少打一些字,或者能增 強代碼的可讀)才會請出它來。好了,言歸正轉,現在我要將一個代碼片段有規律地重復N次,更具體點,就是在定義一個模板的時候,參數列表會很長,但是這些 參數的名字是很有規律地:依次為typename T1,typename T2,....typename TN:
在C++還沒有支持模板的List參數(《C++ template》第13章)之前,我們可以利用宏來減少我們的工作量。
想一下吧,如果問題變了,現在的問題是要你寫一個函數打印出上面的模板參數列表,你會怎么干?拿到這個需求時,我寫下了兩個函數:
-
printMetaExpr: 接收一個參數i,打印出
typename
Ti,
- print:接收一個參數N,作為需要打印的參數個數,然后在一個for循環中調用printMetaExprN次.
如下:
|
|
宏其實也和stream差不多,只不過宏不是把這些東西輸出到控制臺或者文件中,而是輸出給編譯器看的,本質上沒什么區別,所以我們可以這樣來設計我們的宏:
- 定義宏DEFINE_TEMPLATE_PARAM(N),來展開typename TN,這個比較簡單:#define DEFINE_TEMPLATE_PARAM(N) typename T##N
- 定義一個可以調用DEFINE_TEMPLATE_PARAM的宏CALL_MACRO(N,callee,sep):這個宏會調用callee N次,并且每一次調用后都會加上一個分隔sep.
難點就在每二步了,如何來循環調用宏呢?搔頭了吧,其實也不是十分地難,還是拿上面打印到控制臺的程序來說吧,如果你將print寫了成遞歸的形式,一切就真相大白啦:
按照這個思路,如果說我們要支持最多可以調用5次,我們就可以寫出下面的遞歸宏啦:
最后用下面的宏封裝一下上面的宏
#define CALL_MACRO(N,callee) CALL_MACRO##N(callee)
為了驗證上述宏的正確性,我向大家隆重介紹一個可以調試宏的宏:
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
好了,現在可以寫一個簡單地程序來測試一下成果啦:
運行后輸出:
下面給出我使用宏的一點心得:
宏的性質:
- #可以將傳入的參數變為字符串,PRINT_MACRO使用了這個思想,##用以連接宏參數和其他的字符,例如如果有宏
1
|
#defineMEMBER(name) m_##name;
|
調用 MEMBER(Num) 你會得到 m_Num;
- 宏不能實現真正意義上的遞歸調用,例如:
1
|
#define Add(n) Add(n – 1) + n
|
調用Add(3),你將得到:Add(3 – 1) + 3,這恐怕不是你想要的。為了實現宏的遞歸調用必須像上面定義CALL_MACRO一樣一步步地遞歸。
- 我將宏分成了兩類:
(1)值宏,例如: #define __COMMA__ ,
(2)函數宏,例如CALL_MACRO。函數宏又分為兩種
I. 可調用宏,也就是可以作為其他宏的參數被調用,例如DEFINE_TEMPLATE_PARAM
II.不可調用宏,由于#和##的存在。例如: CALL_MACRO
- 定義一個宏時要注意的是:
(1).只將宏用在展開代碼的時候。其他的功能用inline函數和模板代替吧。
(2).如果你在寫一個可調用宏,對于傳入的函數宏,要讓它可以展開,值宏只能在最下層展開.比如逗號,為了讓它只在最底層展開,你可以這樣來定義它:
.傳參時,傳入_COMMA_,在最底層調用時,用_COMMA_(1)
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
