天天看點

C++模闆參數替換的了解

還是鄧俊輝老師資料結構中List那一章的例子。

List的周遊問題。

main.cpp裡調用

<code>PRINT ( La ); // La是一個自定義的List對象</code>

PRINT這個宏的定義就在main.cpp裡

<code>#define PRINT(x) { print(x); crc(x); checkOrder(x); }</code>

print的聲明在UniPrint/print.h裡

注意C++模闆類的定義和實作必須要在同一個檔案中,通常是頭檔案,因為編譯器要看到模闆實作才能展開模闆。

但是print.h裡的模闆類UniPrint隻有方法的聲明,沒有方法的實作。

是以print.h的末尾引入了print_implementation.h這個頭檔案。UniPrint::p的實作就在這個頭檔案裡。

這也是C++模闆類的常用寫法。

print_implementation.h裡又引入了Print_traversable.h,UniPrint::p的真正實作在Print_traversable.h裡。(windows上C++頭檔案不分大小寫)

print_traversable.h

運作到<code>s.traverse( print );</code>這一句的時候會跳到traverse方法裡去。

list.h

從traverse方法來看,它接收的是一個函數指針,這個函數接收一個T型引用的參數,且沒傳回值。

是以s.traverse ( print );中print方法也應該接收一個T型引用的參數。

縱觀print.h中隻有這一句符合條件:<code>template &lt;typename T&gt; static void print ( T&amp; x ) { UniPrint::p ( x ); }</code>

咦?不對呀,這怎麼又回來了?怕不是死循環?

是的,這個地方卡了我好久。後來我想通了。PRINT裡調用print的時候,會先走到print_traversable.h裡去執行UniPrint::p的實作,

執行到s.traverse(print);這一句後,是在traverse這個方法裡調用print的。這個時候UniPrint::p和traverse裡的T已經被替換成int類型了。

也就是模闆已經被執行個體化了。是以debug的時候發現,雖然程式又走到了

print.h中的這一句:<code>template &lt;typename T&gt; static void print ( T&amp; x ) { UniPrint::p ( x ); }</code>

但不會再次走到print_traversable.h裡,因為T已經被替換了。 此時程式會找 <code>void print(int&amp; x){UniPrint::p(x);}</code>的實作,

也就是這裡:

print_basic.cpp

<code>void UniPrint::p ( int e ) { printf ( " %04d", e ); }</code>

C++中沒有print函數。這個print是自己定義的喲。

搞清楚了這個, <code>#define PRINT(x) { print(x); crc(x); checkOrder(x); }</code>裡crc(x)就好了解了。幾乎是同樣的道理。

crc_list

crc_Elem.h

所謂函數對象就是定義了調用操作符()的類對象。當用該對象調用此操作符時,其表現形式如同普通函數調用一般,是以取名叫函數對象

與print不同的地方在于這裡調用的是traverse的另一個版本:

List_traverse.h

看,visit加一個圓括号,就是在用Crc重載後的運算符()。

對了,這個int什麼時候傳進去的?

在調用PRINT宏之前,在main函數這裡傳進去的:

<code>testList&lt;int&gt; ( atoi ( argv[1] ) );</code>

testList也是一個模闆方法: