亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Pure C++:泛型編程:模板特殊化

2019-11-17 05:49:06
字體:
來源:轉載
供稿:網友
    在上一期專欄中我已經談到過,執行的操作不僅包括簡單存儲和檢索操作的參數化類型僅限于可安全綁定到它的可接受類型 [請參閱 Pure C++: CLR Generics Versus C++ Templates(英文)]。使用泛型,可以通過 where 子句顯式加上這些限制。
在 C++/CLI 模板工具中,通過將函數模板或類模板(單個成員函數或整個類)非凡化,通??梢员苊膺@些限制。例如,將 min 函數添加到上一期專欄的 tStack 類中。通常,我會使用常規 min 算法,但那種算法僅在我作為程序員的時候有用,而對我撰寫有關模板非凡化的文章沒有幫助。為了方便起見,圖 1 中重現了 tStack 類的模板定義。    圖 2 顯示了 min 的一種可能的實現方法。我將定義一個局部變量 min_val 來存放最小元素,并將它初始化為容器的第一個元素。然后定義兩個迭代程序,將每個元素與 min_val 進行比較,假如其值比 min_val 小則為 min_val 重新賦值。現在,您能看出隱含的限制嗎?假如能,則您會得到: if ( *it < min_val )    通常,對于 min 函數,只有能夠使用內置小于 (<) 運算符的類型或本身具有 Operator<() 實例的類型才能綁定到 elemType 的類型。假如某個類型沒有定義 operator<(),并嘗試對此類型的項的 tStack 調用 min,則在 min 中使用無效的比較運算符時將出現編譯時錯誤。例如,System::String 類沒有小于 (<) 運算符(它使用 IComparable 的 CompareTo 方法)。因此,假如我嘗試對使用 String 實例化的 tStack 調用 min,則它在編譯時就會出錯,因為該比較操作失敗了。    有一種解決方案我不會使用:定義全局運算符 operator<(),該運算符使用 CompareTo 來比較兩個 String 類型的值。然后,tStack<String^>::min() 會自動調用這些全局運算符: bool operator<( String^ s1, String^ s2 ) {return ( s1->CompareTo( s2 ) < 0 ) ? true :false;}    請記住,目標是防止當用戶指定的類型參數為 String 時實例化 tStack::min 成員函數定義,而希望使用 CompareTo 方法來定義自己的 tStack<String^>::min 實例。您可以使用顯式模板非凡化定義為類模板實例化的成員提供非凡化的定義,來實現此目的。此定義指明了模板名稱、指定模板的參數、函數參數列表和函數主體。要害字模板的后面是小于 (<) 和大于 (>) 標記,然后是類成員非凡化的定義(請參閱圖 3)。    即使類的類型 tStack<String^> 是從常規類模板定義(即由編譯器內部生成的專用于 String 的實例,其中每個 elemType 占位符都被替換為 String 類型)實例化的,類型 tStack<String^> 的每個對象都會調用非凡化的成員函數 min。tStack::min 成員函數定義既不會被擴展,也不會在 tStack<String^> 中使用。    在有些情況下,可能整個類模板定義都不適合某種類型。在這種情況下,程序員可以提供一種定義來非凡化整個類模板。程序員可以提供 tStack<String^> 的定義: template <class elemType>ref class tStack;// 類模板非凡化template<> ref class tStack<String^> {public:tStack();String^ pop();void push( Stack^ et ); // ...};    只有在聲明了常規類模板后,才能定義顯式類模板非凡化。假如您提供完整的類模板非凡化,則必須定義與此非凡化關聯的每個成員函數或靜態數據成員。類模板的常規成員定義決不能用于創建顯式非凡化的成員定義,也不會被交叉檢查。這是因為類模板非凡化的類成員集可能與常規模板的類成員集完全不同。    定義完全非凡化的類模板(如 tStack<String^>)的成員時,請勿在其定義前添加非凡的 template<> 標記,而應該通過顯式列出實際的類型來指明非凡化定義,如下所示: // 定義類模板非凡化的// 成員函數 min()String^ tStack<String^>::min() { ... }
局部模板非凡化
    假如類模板有多個模板參數,您可以針對一個或一組特定的參數化值或類型來非凡化類模板。也就是說,您可能希望提供一個模板,使其除了某些模板參數已被實際類型或實際值替換以外,其他均與常規模板匹配。使用局部模板非凡化就可以實現此目的。例如,假設存在下面的 Buffer 類模板: template <class elemType, int size>ref class Buffer { ... };下面說明如何對 Buffer 使用局部非凡化,使其能夠很好地處理大小為 1KB 的緩沖區: // 類模板 Buffer 的局部非凡化template <class elemType>ref class Buffer<elemType,1024> {// 對 1KB 大小使用非凡算法...};    Buffer 的局部非凡化只有一個類型參數 elemType,因為大小的值固定為 1024。局部模板非凡化的參數列表只列出了模板參數仍然未知的參數。但是,當您定義該模板的實例時,必須同時指定這兩個參數(這與對一個參數使用默認值的情形不同)。在下面的示例中,局部類模板非凡化是用 elemType 為 String 的類型參數實例化的: Buffer<String^,1024> mumble;但是,假如您改為下面的代碼行,則編譯器會生成錯誤,并將聲明標記為缺少第二個參數: Buffer<String^> mumble; // 錯誤為什么會這樣呢?假如開發人員以后引入一組非凡化的 Buffer(如下所示),會出現什么情況? template <class elemType>ref class Buffer<elemType,4096> {};template <class elemType> ref class Buffer<elemType,512> {};假如前面示例的聲明中不要求使用第二個參數,編譯器就無法區分這幾種非凡化!    局部非凡化與其對應的完整常規模板同名,在本例中為 Buffer。這就帶來了一個有趣的問題。請注重,Buffer<String^,1024> 的實例化既可以通過類模板定義進行,也可以通過局部非凡化進行。那么,為什么會選擇局部非凡化來實例化該模板呢?一般的規則是:假如聲明了局部類模板非凡化,編譯器就會選擇最非凡化的模板定義進行實例化。只有在無法使用局部非凡化時,才會使用常規模板定義。    例如,當必須實例化 Buffer<String^,2048> 時,由于此實例化與任何一個局部模板非凡化都不匹配,因此會選擇常規模板定義。    局部非凡化的定義完全不同于常規模板的定義。局部非凡化可以擁有一組與常規類模板完全不同的成員。局部類模板非凡化的成員函數、靜態數據成員和嵌套類型必須有自己的定義,這與類模板非凡化相同。類模板成員的常規定義決不能用于實例化局部類模板非凡化的成員。    類模板的局部模板非凡化構成了現代 C++ 用法中一些非常復雜的設計慣用語的基礎。假如您對此感愛好,可以閱讀 Andrei Alexandrescu 撰寫的《Modern C++ Design: Generic PRogramming and Design Patterns Applied》(Addison-Wesley,2001 年版),了解此用法的具體信息。
進入討論組討論。
函數模板非凡化    非成員函數模板也可以進行非凡化。在有些情況下,您可以充分利用有關類型的一些專門知識,來編寫比從模板實例化的函數更高效的函數。在其他一些情況下,常規模板的定義對某種類型而言根本就是錯誤的。
例如,假設您擁有函數模板 max 的定義: template <class T>T max( T t1, T t2 ) {return ( t1 > t2 ? t1 :t2 );}    假如用 System::String 類型的模板參數實例化該函數模板,所生成的實例就無法編譯,因為正如您在前面所看到的,String 類不支持小于 (<) 或大于 (>) 運算符。圖 4 中的代碼說明了如何非凡化函數模板。(同樣必須先聲明常規函數模板才能進行非凡化。)    假如可以從函數參數推斷出模板參數,則可以從顯式非凡化聲明中對實際類型參數省略函數模板名稱的限定 max<String^>。例如,編譯器可以在下面的 max 模板非凡化中推斷出 T 綁定到 String,因此在這種情況下,為方便起見,該語言答應使用下面的簡寫表示法: // 沒問題:從參數類型推斷出 T 綁定到 Stringtemplate<> String^ max( String^, String^ );引入此顯式非凡化后,下面的調用就會解析為這個非凡化的實例: void foo( String^ s1, String^ s2 ) {String^ maxString = max( s1, s2 ); // ...}
假如兩個參數的類型均為 String,常規函數模板不會擴展。這正是我們所需要的行為。只要提供了顯式函數模板非凡化,就必須始終指定 template<> 和函數參數列表。例如,max 的下面兩個聲明不合法,并且在編譯時會被標記為: // 錯誤:無效的非凡化聲明// 缺少 template<>String^ max<String^>( String^, String^ );// 缺少函數參數列表template<> String^ max<String^>;    有一種情況,省略函數模板非凡化的 template<> 部分不是錯誤。即,在您聲明的普通函數帶有與模板實例化相匹配的返回類型和參數列表的情況下: // 常規模板定義template <class T>T max( T t1, T t2 ) { /* ... */ }// 沒問題:普通函數聲明!String^ max( String^, String^ );    毫無疑問,您經常會感到很無奈,并認為 C++ 真是太難理解了。您可能想知道,究竟為什么所有人都希望聲明與模板實例化相匹配的普通函數,而不希望聲明顯式非凡化。那么,請看下面的示例,事情并不是完全按照您喜歡的方式進行的: void foo( String^ s1, String^ s2 ) {// 能否解析非凡化的實例?String^ maxString = max( "muffy", s2 ); // ... }在 C++/CLI 下,對于重載解決方案,字符串文字的類型既是 const char[n] [其中 n 是文字的長度加一(用于終止空字符)],又是 System::String。這意味著,給定一組函數 void f( System::String^ ); // (1)void f( const char* ); // (2)void f( std::string ); // (3)如下所示的調用 // 在 C++/CLI 下解析為 (1)f( "bud, not buddy" );    與 (1) 完全匹配,而在 ISO-C++ 下,解析結果會是 (2)。因此,問題就是,對于函數模板的類型推斷而言,字符串文字是否還是被當作 System::String 進行處理?簡言之,答案是“不”。(具體的答案將是我下一期專欄的主題,該專欄將具體介紹函數模板。)因此,不選擇 max 的非凡化 String 實例,下面對 max 的調用 String^ maxString = max( "muffy", s2 ); // 錯誤在編譯時會失敗,因為 max 的定義要求兩個參數的類型均為 T: template <class T> T max( T t1, T t2 );那您能做些什么呢?像在下面的重新聲明中一樣,將模板改為帶有兩個參數的實例 template <class T1,class T2> ??? max( T1 t1, T2 t2 );    使我們能夠編譯帶有 muffy 和 s2 的 max 的調用,但會因大于 (>) 運算符而斷開;并且指定要返回的參數類型。     我想做的就是始終將字符串文字強制轉換為 String 類型,這也是拯救普通函數的方法。    假如在推斷模板參數時使用了某個參數,那么只有一組有限的類型轉換可用于將函數模板實例化的參數轉換為相應的函數參數類型。還有一種情況是顯式非凡化函數模板。正如您所看到的,從字符串文字到 System::String 的轉換不屬于上述情況。    在存在有害字符串文字的情況下,顯式非凡化無助于避免對類型轉換的限制。假如您希望不僅答應使用一組有限的類型轉換,則必須定義普通函數而不是函數模板非凡化。這就是 C++ 答應重載非模板函數和模板函數的原因。進入討論組討論。
    我基本上已經講完了,不過還有最后一點需要說明。創建一組您在圖 5 中看到的 max 函數意味著什么?您知道調用 max( 10, 20 );始終會解析為常規模板定義,并將 T 推斷為 int。同樣,您現在還知道調用
max( "muffy", s2 );max( s2, "muffy" );始終會解析為普通函數實例(其中文字字符串轉換為 System::String),但是有一個問題,調用 max( s2, s2 );會解析為三個 max 函數中的哪一個?要回答此問題,我們要查看解析重載函數的過程。
重載函數的解析過程
    解析重載函數的第一步是建立候選函數集。候選函數集包含與被調用的函數同名并且在調用時能夠看到其聲明的函數。    第一個可見函數是非模板實例。我將該函數添加到候選列表中。那么函數模板呢?在能夠看到函數模板時,假如使用函數調用參數可以實例化函數,則該模板的實例化被視為候選函數。在我的示例中,函數參數為 s2,其類型為 String。模板參數推斷將 String 綁定到 T,因此模板實例化 max(String^,String^) 將添加到候選函數集中。    只有在模板參數推斷成功時,函數模板實例化才會進入候選函數集。但是,假如模板參數推斷失敗,不會出現錯誤;即,函數實例化沒有添加到候選函數集中。    假如模板參數推斷成功,但是模板是為推斷出的模板參數顯式非凡化的(正如我的示例一樣),會怎么樣呢?結果是,顯式模板非凡化(而不是通過常規模板定義實例化的函數)將進入候選函數。因此,此調用有兩個候選函數:非凡化的模板實例化和非模板實例。 // 候選函數// 非凡化的模板...template<> String^ max<String^>( String^ s1, String^ s2 );// 非模板實例String^ max( String^, String^ );    解析重載函數的下一步是從候選函數集中選擇可行函數集。對于要限定為可行函數的候選函數,必須存在類型轉換,將每個實際參數類型轉換為相應的形式參數類型。在該示例中,兩個候選函數都是可行的。    解析重載函數的最后一步是,對參數所應用的類型轉換進行分級,以選擇最好的可行函數。例如,兩個函數看起來都很好。既然兩個函數都可行,那么這是否應該被視為不明確的調用?    實際上,調用是明確的:將調用非模板 max,因為它優先于模板實例化。原因是,在某種程度上,顯式實現的函數比通過常規模板創建的實例更為實用。    令人吃驚的是,在解決有害字符串文字的情況中,我已經徹底消除了調用以前的 String 非凡化的可能性,因此我可以消除這個問題。我只需要常規模板聲明以及重載的非模板實例: // 支持 String 的最終重載集template <class T>T max( T t1, T t2 ) { /* ... */ }String^ max( String^, String^ );    這不一定會很復雜,但有一點是肯定的 - 在語言集成和靈活性方面,它遠遠地超過了公共語言運行時 (CLR) 泛型功能可以支持的范圍。     模板非凡化是 C++ 模板設計的基礎。它提供了最好的性能,克服了對單個或系列類類型的限制,具有靈活的設計模式,并且在實際代碼中已證實其巨大價值。在下一期專欄中,我將深入分析 C++/CLI 對模板函數和常規函數的支持。
請將您的疑問和意見通過 purecpp@microsoft.com 發送給 Stanley。Stanley B. Lippman 是 Microsoft 公司 Visual C++ 團隊的體系結構設計師。他從 1984 年開始在 Bell 實驗室與 C++ 的設計者 Bjarne Stroustrup 一起研究 C++。此后,他在 Disney 和 DreamWorks 制作過動畫,還擔任過 JPL 的高級顧問和 Fantasia 2000 的軟件技術主管。轉到原英文頁面進入討論組討論。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩精品在线视频美女| 日本国产一区二区三区| 日韩电影网在线| 亚洲视频自拍偷拍| 国产成人精品优优av| 亚洲第一区在线观看| 国产成人精品日本亚洲专区61| 国产精品久久久久免费a∨大胸| 日韩av一区二区在线| 在线观看国产精品淫| 亚洲欧美日韩国产成人| 亚洲电影免费观看高清完整版在线观看| 欧美最近摘花xxxx摘花| 亚洲欧美日韩精品久久奇米色影视| 欧美一级黑人aaaaaaa做受| 亚洲精品免费一区二区三区| 国产精品入口免费视| 国产午夜精品视频免费不卡69堂| 日本中文字幕不卡免费| 国产精品久久久久久久久| 日韩高清有码在线| 亚洲成人网久久久| 91精品国产91久久久久久久久| 国产精品免费久久久| 日韩中文字幕在线播放| 91精品久久久久久久久久| 高清欧美电影在线| 欧美极品少妇xxxxⅹ裸体艺术| 久久精品国产欧美激情| 亚洲人成电影网| 国产精品h片在线播放| 国产精品大片wwwwww| 国产成人欧美在线观看| 久久精品国产成人| 亚洲一区二区三区香蕉| 国产精品久久一| 97在线精品国自产拍中文| 欧美日本中文字幕| 欧美久久精品午夜青青大伊人| 国产精品自拍小视频| 久久人人爽人人爽人人片av高请| 亚洲最大av网| 一区二区欧美亚洲| 亚洲一区亚洲二区| 亚洲另类图片色| 日韩av观看网址| 欧美日韩国产限制| 亚洲一区二区黄| 国产精品老女人视频| 九九视频直播综合网| 亚洲级视频在线观看免费1级| 国产精品视频午夜| 精品欧美aⅴ在线网站| 91色琪琪电影亚洲精品久久| 三级精品视频久久久久| 91亚洲va在线va天堂va国| 国产精品入口免费视| 精品福利视频导航| 91欧美精品午夜性色福利在线| 欧美成人亚洲成人日韩成人| 91精品久久久久久久久久入口| 成人性教育视频在线观看| 久久频这里精品99香蕉| 在线电影av不卡网址| 欧美一区二区大胆人体摄影专业网站| 国产精品亚洲视频在线观看| 日韩精品在线播放| 精品丝袜一区二区三区| 日韩精品免费在线播放| 亚洲精品一区久久久久久| 国产精品高潮呻吟久久av无限| 午夜精品一区二区三区在线视| 国产精品青草久久久久福利99| www.亚洲免费视频| 国产精品日日做人人爱| 欧美成在线观看| 国产精品视频精品视频| 国产精品一区二区电影| 国产精品91免费在线| 亚洲成av人片在线观看香蕉| 日本三级韩国三级久久| 欧美国产亚洲视频| 国产欧美一区二区三区四区| 欧美黑人性生活视频| xvideos成人免费中文版| 国产在线精品一区免费香蕉| 日韩av在线电影网| 日韩免费精品视频| 欧美性猛交xxxx偷拍洗澡| 亚洲视频自拍偷拍| 精品无人区乱码1区2区3区在线| 欧美亚洲国产视频| 黑人巨大精品欧美一区二区免费| 精品国内自产拍在线观看| www.久久久久| 欧美丰满老妇厨房牲生活| 欧洲成人免费aa| 最新69国产成人精品视频免费| 热99精品只有里视频精品| 日韩视频免费在线| 欧美性生交xxxxx久久久| 国产精品久久久久久久久久久新郎| 成人www视频在线观看| 欧美成年人网站| 91久久精品久久国产性色也91| 欧美日韩精品中文字幕| 成人性生交大片免费看视频直播| 久久成人免费视频| 色噜噜狠狠狠综合曰曰曰88av| 91久久精品一区| 成人午夜黄色影院| 久久久久久com| 中文字幕精品—区二区| 成人欧美在线视频| 亚洲天堂免费观看| 亚洲在线免费观看| 日韩av手机在线看| 亚洲国产日韩欧美在线图片| xvideos国产精品| 国产日韩欧美夫妻视频在线观看| 欧美成人午夜视频| 亚洲第一国产精品| 欧美日韩一二三四五区| 久久久国产影院| 欧美午夜精品久久久久久浪潮| 欧美一区二区三区图| 亚洲天堂av在线播放| 久久久久久国产精品三级玉女聊斋| 亚洲影影院av| 欧美华人在线视频| 亚洲精品色婷婷福利天堂| 色七七影院综合| 欧美激情亚洲自拍| 日韩精品极品在线观看| 亚洲一区二区国产| 国产精品视频久久久久| 性日韩欧美在线视频| 久久精品99国产精品酒店日本| 国产精品com| 久久99国产综合精品女同| 永久免费精品影视网站| 清纯唯美日韩制服另类| 久久夜色撩人精品| 精品国产依人香蕉在线精品| 久久全球大尺度高清视频| 欧美高清视频在线播放| 欧洲成人在线视频| 久久久免费高清电视剧观看| 97精品伊人久久久大香线蕉| 日韩精品免费电影| 成人羞羞国产免费| 中文字幕欧美精品在线| 国产美女精品视频免费观看| 国产精品久久久久久久久久| 亚洲人成欧美中文字幕| 51视频国产精品一区二区| 欧美黄色www| 日韩精品中文字幕久久臀| 久久久精品欧美| 久久久久免费视频| 在线日韩日本国产亚洲| 97免费视频在线播放| 欧美日韩亚洲一区二| 91亚洲国产成人精品性色|