成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++ 模板元編程之模板特化的概念從何而來

開發 后端
C++ 里的模板能做什么呢?它好比 C 語言中的宏、C# 和 Java 中的自省(restropection)和反射(reflection),是 C++ 語言的外延。

0. 前言

C++ 里的模板能做什么呢?它好比 C 語言中的宏、C# 和 Java 中的自省(restropection)和反射(reflection),是 C++ 語言的外延。更極端一點地理解:它是一門新的圖靈完備的編程語言(也就是說,C++ 模板能實現圖靈機模型里的全部功能)。在《Modern C++ Design》中,作者拋出了以下幾個問題:

(1)如何撰寫更高級的C++程式?

(2)如何應付即使在很干凈的設計中仍然像雪崩一樣的不相干細節?

(3)如何構建可復用組件,使得每次在不同程式中應用組件時無需大動干戈?

解決上述問題的方法就是模板元編程。元(meta)本身就是個很“抽象(abstract)”的詞,因為它的本意就是“抽象”。元編程,也可以說就是“編程的抽象”。用更好理解的說法,元編程意味著你撰寫一段程序A,程序A會運行后生成另外一個程序B,程序B才是真正實現功能的程序。那么這個時候程序A可以稱作程序B的元程序,撰寫程序A的過程,就稱之為“元編程”。

C++中,元編程的手段,可以是宏,也可以是模板。

1、為什么需要泛型編程:從宏到模板,再到元編程

如果元編程中所有的變量(或者說元編程的參數),都是類型,那么這樣的編程,我們有個特定的稱呼,叫“泛型”。

模板的發明,僅僅是為了做和宏幾乎一樣的替換工作嗎?可以說是,也可以說不是。

一方面,模板可以用來替換類型,這點和宏沒什么區別。只是宏在編譯階段基于文本做純粹替換,被替換的文本本身沒有任何語義。而模板會在分析模板時以及實例化模板的時候都會進行檢查,而且源代碼中也能與調試符號一一對應,所以無論是編譯時還是運行時,排錯都相對簡單。

另一方面,模板和宏也有很大的不同,模板最大的不同在于它是“可以運算”的。我們來看一個例子:

  1. void Add(uint8_t, unit8_t) {} 

上述函數實現了一個 uint8_t 和 uint8_t 類型的加法運算,如果現在要實現 int16 和 int16 類型的加法運算,該怎么辦呢?簡單點的方法如下:

  1. if (type == 8) { 
  2.     Add(uint8_t, uint8_t) 
  3. else if (type == 16) { 
  4.     Add(uint16_t, uint16_t) 

但是這里有兩個難點:

  • 首先, if(type == x) 是不存在于 C++ 中的
  • 其次,即便存在獲取變量 type 的方法(Boost.Any 中的 typeid ),我們也不希望它在運行時判斷,這樣會變得很慢。是否可以不引入 if/else,在編譯期就把 Add 的方法確定呢?

有人說,重載、虛函數也能解決如上問題:

  1. void Add(uint8_t, uint8_t) {} 
  2. void Add(uint16_t, uint16_t) {} 

甚至在 C 語言中定義新的結構體 Variant 或使用 void* 也能解決該問題:

  1. struct Variant 
  2.     union 
  3.     { 
  4.         uint_8 x; 
  5.         uint_16 y; 
  6.     } data; 
  7.     uint32_t typeId; 
  8. }; 

沒錯,但是如果我還有 uint9_t、uint10_t 等各種類型的加法運算呢?Anyway,不管是哪種方法都很難避免 if/else 的存在。

模板與上述這些方法最大的區別在于:模板無論其參數或者是類型,它都是一個編譯期分派的方法。編譯期就能確定的東西既可以做類型檢查,編譯器也能進行優化,砍掉任何不必要的代碼執行路徑。

2、類模板的特化:模板世界里的 if/else

2.1 根據類型執行代碼

我們先來看看一個模板的例子:

  1. template <typename T> T AddFloatOrMulInt(T a, T b); 
  2. // 我們希望這個函數在 T 是 float 的時候做加法運算,在 T 是 int 類型的時候做乘法運算 

那么當傳入兩個不同類型的變量,或者不是 int 和 float 變量,編譯器就會提示錯誤。

從能力上來看,模板能做的事情都是編譯期完成的。編譯期完成的意思就是,當你編譯一個程序的時候,所有的量就都已經確定了。比如下面的例子:

  1. int a = 3, b = 5; 
  2. Variant aVar, bVar; 
  3. aVar.setInt(a);            // 我們新加上的方法,怎么實現的無所謂,大家明白意思就行了。 
  4. bVar.setInt(b); 
  5. Variant result = AddFloatOrMulInt(aVar, bVar); 

從上述代碼中我們可以看到:aVar 和 bVar 都一定會是整數。所以如果有合適的機制,編譯器就能知道此處的 AddFloatOrMulInt 中只需要執行 int 路徑上的代碼,而且編譯器在此處也能單獨為 int 路徑生成代碼,從而去掉那個不必要的 if。在模板代碼中,這個“合適的機制”就是指“特化”和“部分特化(Partial Specialization)”,后者也叫“偏特化”。

2.2、如何寫模板特化的代碼

1.0 版本 - 偽代碼

  1. int/float AddFloatOrMulInt(a, b) // 類的靜態函數 
  2.   if(type is int) { 
  3.     return a * b; 
  4.   } else if (type is float) { 
  5.     return a + b; 
  6.   } 
  7.  
  8. void foo() 
  9.     float a, b, c; 
  10.     c = addFloatOrMulInt(a, b);        // c = a + b; 
  11.  
  12.     int x, y, z; 
  13.     z = addFloatOrMulInt(x, y);        // z = x * y; 

2.0 版本 - 函數重載

  1. float AddFloatOrMulInt(float a, float b) 
  2.     return a + b; 
  3.  
  4. int AddFloatOrMulIntDo(int a, int b) 
  5.     return a * b; 
  6.  
  7. void foo() 
  8.     float a, b, c; 
  9.     c = AddFloatOrMulInt(a, b);        // c = a + b; 
  10.  
  11.     int x, y, z; 
  12.     z = AddFloatOrMulInt(x, y);        // z = x * y; 

3.0 版本 - 純模板

  1. // 這個是給float用的。 
  2. template <typename T> class AddFloatOrMulInt 
  3.     T Do(T a, T b) 
  4.     { 
  5.         return a + b; 
  6.     } 
  7. }; 
  8.  
  9. // 這個是給int用的。 
  10. template <typename T> class AddFloatOrMulInt 
  11.     T Do(T a, T b) 
  12.     { 
  13.         return a * b; 
  14.     } 
  15. }; 
  16.  
  17. void foo() 
  18.     float a, b, c; 
  19.  
  20.     // 我們需要 c = a + b; 
  21.     c = AddFloatOrMulInt<float>::Do(a, b);         
  22.     // ... 覺得哪里不對勁 ... 
  23.     // 啊!有兩個 AddFloatOrMulInt,class 看起來一模一樣,要怎么區分呢! 

好吧,問題來了!如何要讓兩個內容不同,但是模板參數形式相同的類進行區分呢?特化!特化(specialization)是根據一個或多個特殊的整數或類型,給出模板實例化時的一個指定內容。

4.0 版本 - 模板特化

  1. // 首先,要寫出模板的一般形式(原型,即初始化,不能省) 
  2. template <typename T> class AddFloatOrMulInt 
  3.     static T Do(T a, T b)  // 注意這里必須得是靜態方法!!! 
  4.     { 
  5.         return T(0); 
  6.     } 
  7. }; 
  8.  
  9. // 其次,我們要指定T是float時候的代碼: 
  10. template <> class AddFloatOrMulInt<float
  11. public
  12.     static float Do(float a, float b) 
  13.     { 
  14.         return a + b; 
  15.     } 
  16. }; 
  17.  
  18. // 再次,我們要指定T是int時候的代碼,這就是特化: 
  19. template <> class AddFloatOrMulInt<int
  20. public
  21.     static int Do(int a, int b) //  
  22.     { 
  23.         return a * b; 
  24.     } 
  25. }; 
  26.  
  27. int foo() 
  28.     return AddFloatOrMulInt<float>::Do(1.0, 2.0); 
  29.  
  30. int main()  
  31.     std::cout << foo();  // 輸出結果 3.0 

解釋:

  1. // 我們這個模板的基本形式是什么? 
  2. template <typename T> class AddFloatOrMulInt; 
  3.  
  4. // 但是這個類,是給T是 int 的時候用的,于是我們寫作 
  5. class AddFloatOrMulInt<int>; 
  6. // 當然,這里編譯是通不過的。 
  7. // 但是它又不是個普通類,而是類模板的一個特化(特例)。 
  8. // 所以前面要加模板關鍵字template,以及模板參數列表 
  9. template </* 這里要填什么? */> class AddFloatOrMulInt<int>; 
  10.  
  11. // 最后,模板參數列表里面填什么?因為原型的T已經被int取代了。所以這里就不能也不需要放任何額外的參數了。所以這里放空。 
  12. template <> class AddFloatOrMulInt<int
  13.     // ... 針對 int 的實現 ...  
  14.  
  15. // Done! 

至此,第一個模板特化的代碼已經寫完了。這里的 AddFloatOrMulInt 如同是一個函數,卻只能在編譯期間執行。如果你體味到了這一點,那么恭喜你,你的模板元編程已經開悟了。

3、總結

 

本文核心只講了兩個問題:一是為什么需要泛型編程,重點介紹了宏、模板和元編程的關系;二是模板類的特化代碼如何編寫。關于特化,還有很多細節知識,在之后的文章中我們繼續探究,另外將還介紹偏特化等知識點,敬請期待。

 

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2010-02-04 13:56:24

C++類模板特化

2021-12-08 13:57:29

以太坊加密貨幣比特幣

2012-06-20 16:51:41

Surface

2020-12-01 12:52:05

物聯網物聯網設備

2009-11-25 10:21:13

Linux中文桌面

2011-07-07 09:12:46

智慧運算WatsonPower

2009-11-19 11:27:01

AMD技術代號

2020-04-20 22:41:14

物聯網安全漏洞IOT

2021-01-08 14:40:56

比特幣加密貨幣區塊鏈

2009-04-01 10:39:37

Hyper-V微軟虛擬機

2014-06-23 09:30:34

華為數據中心鳳凰衛視全媒體

2010-02-03 17:42:33

C++模板參數

2010-05-04 16:36:10

虛擬化

2020-06-24 08:43:29

5G核心網通信

2018-03-26 10:14:05

2020-04-01 14:24:06

機器學習人工智能AI

2023-08-22 08:18:33

Intel顯卡銳炫

2010-02-05 17:34:37

C++函數模板

2020-03-16 14:22:32

蘋果MacBook英特爾
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产欧美精品一区二区色综合朱莉 | 国产日产精品一区二区三区四区 | 国精产品一品二品国精在线观看 | 午夜精品久久久久久久99黑人 | 在线日韩av电影 | 美女一级毛片 | 久久久久亚洲国产| 午夜影院在线观看视频 | 精品一二三区 | 成人高潮片免费视频欧美 | 国产精品久久久久国产a级 欧美日本韩国一区二区 | 人妖av| 国产免费a视频 | 天天干天天谢 | h视频在线免费 | 日韩视频精品在线 | 欧美成人a∨高清免费观看 91伊人 | 久久久久久国产精品免费免费男同 | 欧美日韩国产在线观看 | 欧美三级成人理伦 | 一级免费视频 | 精品久久视频 | 97视频在线观看网站 | 日本欧美国产 | 国产二区在线播放 | av毛片| 最新日韩精品 | 久草.com | 色性av| 久久精品网 | 国产综合在线视频 | 国产一级在线 | 亚洲美女av网站 | 国产精品999| 狠狠av| 日韩精品免费一区 | 一色一黄视频 | 亚洲视频国产 | 久草福利| 中文字幕一区二区三区乱码在线 | 国产精品一区二区av |