在 C++ 中為了操作簡潔引入了函數模板。所謂的函數模板實際上是建立一個通用函數,其函數類型或形參類型不具體指定,用一個虛擬的類型來表達,這個通用函數就稱為函數模板。 1、通用的寫法 函數模板不是一個具體的函數,編譯器不能為其生成可執行代碼。定義函數模板後只是一個對函數功能框架的描述,當它具體執行時 ...
在 C++ 中為了操作簡潔引入了函數模板。所謂的函數模板實際上是建立一個通用函數,其函數類型或形參類型不具體指定,用一個虛擬的類型來表達,這個通用函數就稱為函數模板。
1、通用的寫法
函數模板不是一個具體的函數,編譯器不能為其生成可執行代碼。定義函數模板後只是一個對函數功能框架的描述,當它具體執行時,將根據傳遞的實際參數決定其功能。為了容易使用,一般通用的寫法都是在頭文件中直接定義函數模板,定義的同時也是聲明該函數,供給其它文件包含調用。
1 //------fun.h或fun.hpp------// 2 #ifndef _FUN_H_ 3 #define _FUN_H_ 4 5 using namespace std; 6 7 template<typename T> 8 void fun(int b, T c, T d) //定義函數模板 9 { 10 ...... 11 } 12 13 #endif
對編譯器而言,定義函數模板的時候,編譯器並不會對它進行編譯,因為它沒有一個實體可用,編譯器只看到了聲明,只有模板被實例化後(用在特定的類型上),編譯器才會根據具體的類型對模板進行編譯。因此當在別的文件中調用該函數模板時,根據傳遞的實際參數決定其功能,這樣編譯器就可以在編譯期間看到模板函數的定義並完成模板的實例化,如果在編譯的時候,找不到模板函數的定義,就先不在這一次編譯中實例化該模板函數。
2、問題的引出
但是頭文件中定義和使用函數模板時,碰到了一個這樣的場景,即在函數模板中使用到了全局變數:
1 //------fun.h或fun.hpp------// 2 #ifndef _FUN_H_ 3 #define _FUN_H_ 4 5 using namespace std; 6 int a; //定義全局變數 7 template<typename T> 8 void fun(int b, T c, T d) //定義函數模板 9 { 10 ...... 11 a = b; 12 } 13 14 #endif
因此碰到其它多個文件需要使用該函數模板時,都需要各自包含該函數模板的頭文件,編譯時就會出現“全局變數重覆定義”的錯誤。
嘗試按照普通函數定義和聲明分開的思路將函數模板的定義和聲明分開:
源文件:
1 //------fun.cpp------// //錯誤做法 2 using namespace std; 3 int a; //定義全局變數 4 template<typename T> 5 void fun(int b, T c, T d) //定義函數模板 6 { 7 ...... 8 a = b; 9 }
頭文件:
1 //------fun.h或fun.hpp------// //錯誤做法 2 #ifndef _FUN_H_ 3 #define _FUN_H_ 4 5 extern a; 6 template<typename T> void fun(int b, T c, T d); 7 8 #endif
經過嘗試,按照普通函數的方式將函數模板的定義和聲明分開,在其它文件中調用函數模板,編譯時就會出現“找不到該函數定義”的錯誤。
那麼有沒有辦法將函數模板的定義和聲明正確分開,提供給其它文件包含調用呢,答案肯定是有的。
3、問題的解決
針對上述第2點所闡述的函數模板使用的這一場景,需要將函數模板的定義和聲明分離開來,根據實際的應用,使用以下的做法可以很好的解決這一問題,編譯和調用都沒有問題。
首先是源文件*.cpp的實現:
1 //------fun.cpp------// 2 using namespace std; 3 int a; //定義全局變數 4 template<typename T> 5 void fun(int b, T c, T d) //定義函數模板 6 { 7 ...... 8 a = b; 9 } 10 11 template void fun(int b, int c, int d); //函數模板實例化,此時T被int替代 12 template void fun(int b, char c, char d); //函數模板實例化,此時T被char替代
因此在源文件中操作有:
(1)、定義需要使用的函數模板;
(2)、在定義的函數模板後進行函數實例化操作,通過這樣的方法實現具體的模板函數。
接著是頭文件*.h或者*.hpp的實現:
1 //------fun.h或fun.hpp------// 2 #ifndef _FUN_H_ 3 #define _FUN_H_ 4 5 extern a; 6 template<typename T> void fun(int b, T c, T d); 7 extern template void fun(int b, int c, int d); 8 extern template void fun(int b, char c, char d); 9 10 #endif
因此在頭文件中需要的操作有:
(1)、聲明定義的函數模板;
(2)、使用extern的方式聲明實例化後的模板函數。
總結
可見,將函數模板的定義和聲明分開,需要額外在源文件中進行函數模板的實例化再在頭文件中進行聲明,多了一些步驟。在無特定的使用的場景中,還是建議將函數模板放在頭文件中直接定義並調用;當然,如果碰到一些跨文件調用的特定場景,那麼採用這種將函數模板的定義和聲明分開的方法也是OK的。
更多技術內容和書籍資料獲取敬請關註微信公眾號“明解嵌入式”
本文來自博客園,作者:Sharemaker,轉載請註明原文鏈接:https://www.cnblogs.com/Sharemaker/p/17019826.html