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

首頁 > 編程 > C++ > 正文

淺談C++模板元編程

2020-05-23 13:31:46
字體:
來源:轉載
供稿:網友

所謂元編程就是編寫直接生成或操縱程序的程序,C++ 模板給 C++ 語言提供了元編程的能力,模板使 C++ 編程變得異常靈活,能實現很多高級動態語言才有的特性(語法上可能比較丑陋,一些歷史原因見下文)。模板元編程的根在模板。模板的使命很簡單:為自動代碼生成提供方便。提高程序員生產率的一個非常有效的方法就是“代碼復用”,而面向對象很重要的一個貢獻就是通過內部緊耦合和外部松耦合將“思想”轉化成一個一個容易復用的“概念”。但是面向對象提供的工具箱里面所包含的繼承,組合與多態并不能完全滿足實際編程中對于代碼復用的全部要求,于是模板就應運而生了。

模板是更智能的宏。模板和宏都是編譯前代碼生成,像宏一樣,模板代碼會被編譯器在編譯的第一階段(在內部轉,這點兒與預編譯器不同)就展開成合法的C++代碼,然后根據展開的代碼生成目標代碼,鏈接到最終的應用程序之中。模板與宏相比,它站在更高的抽象層上面,宏操作的是字符串中的token,然而模板卻能夠操作C++中的類型。所以模板更加安全(因為有類型檢查),更加智能(可以根據上下文自動特化)……說完模板,來說說模板元編程。模板元編程其實就是復雜點兒的模板,簡單的模板在特化時基本只包含類型的查找與替換,這種模板可以看作是“類型安全的宏”。而模板元編程就是將一些通常編程時才有的概念比如:遞歸,分支等加入到模板特化過程中的模板,但其實說白了還是模板,自動代碼生成而已。普通用戶對 C++ 模板的使用可能不是很頻繁,大致限于泛型編程,但一些系統級的代碼,尤其是對通用性、性能要求極高的基礎庫(如 STL、Boost)幾乎不可避免的都大量地使用 C++ 模板,一個稍有規模的大量使用模板的程序,不可避免的要涉及元編程(如類型計算)。本文就是要剖析 C++ 模板元編程的機制。

C++ 模板是圖靈完備的,這使得 C++ 成為兩層次語言(two-level languages,中文暫且這么翻譯,文獻[9]),其中,執行編譯計算的代碼稱為靜態代碼(static code),執行運行期計算的代碼稱為動態代碼(dynamic code),C++ 的靜態代碼由模板實現(預處理的宏也算是能進行部分靜態計算吧,也就是能進行部分元編程,稱為宏元編程,見 Boost 元編程庫即 BCCL,具體來說 C++ 模板可以做以下事情:編譯期數值計算、類型計算、代碼計算(如循環展開),其中數值計算實際不太有意義,而類型計算和代碼計算可以使得代碼更加通用,更加易用,性能更好(但是也會讓代碼也更難閱讀,更難調試,有時也會有代碼膨脹問題)。總的來說模板元編程的優勢在于:

1.以編譯耗時為代價換來卓越的運行期性能(一般用于為性能要求嚴格的數值計算換取更高的性能)。通常來說,一個有意義的程序的運行次數(或服役時間)總是遠遠超過編譯次數(或編譯時間)。

2.提供編譯期類型計算,通常這才是模板元編程大放異彩的地方。

模板元編程技術并非都是優點:

1.代碼可讀性差,以類模板的方式描述算法也許有點抽象。

2.調試困難,元程序執行于編譯期,沒有用于單步跟蹤元程序執行的調試器(用于設置斷點、察看數據等)。程序員可做的只能是等待編譯過程失敗,然后人工破譯編譯器傾瀉到屏幕上的錯誤信息。

3.編譯時間長,通常帶有模板元程序的程序生成的代碼尺寸要比普通程序的大,

4.可移植性較差,對于模板元編程使用的高級模板特性,不同的編譯器的支持度不同。

編譯期計算在編譯過程中的位置請見下圖,可以看到關鍵是模板的機制在編譯具體代碼(模板實例)前執行:

C++,模板元,編程

從編程范型(programming paradigm)上來說,C++ 模板是函數式編程(functional programming),它的主要特點是:函數調用不產生任何副作用(沒有可變的存儲),用遞歸形式實現循環結構的功能。C++ 模板的特例化提供了條件判斷能力,而模板遞歸嵌套提供了循環的能力,這兩點使得其具有和普通語言一樣通用的能力(圖靈完備性)。從編程形式來看,模板的“<>”中的模板參數相當于函數調用的輸入參數,模板中的 typedef 或 static const 或 enum 定義函數返回值(類型或數值,數值僅支持整型,如果需要可以通過編碼計算浮點數),代碼計算是通過類型計算進而選擇類型的函數實現的(C++ 屬于靜態類型語言,編譯器對類型的操控能力很強)。

示例: 

#include <iostream> template<typename T, int i = 1> class CComputeSomething { public:   typedef volatile T *retType; // 類型計算   enum {     retValume = i + CComputeSomething<T, i - 1>::retValume   }; // 數值計算,遞歸   static void f() {     std::cout << "CComputeSomething:i = " << i << " retValume = " << retValume << '/n';   } };  //遞歸結束特例 template<typename T> class CComputeSomething<T, 0> { public:   enum {     retValume = 0   }; };  // 根據類型調用函數,代碼計算 template<typename T> class CComputingFunc { public:   static void f() { T::f(); } };  int main() {   CComputeSomething<int>::retType a = 0;   //這里的遞歸深度注意,不同編譯器允許的最大深度不同,編譯時添加 -ftemplate-depth=500來修改編譯器允許的遞歸最大深度   CComputingFunc<CComputeSomething<int, 500>>::f();   return 0; }

C++ 模板元編程概覽框圖如下:

C++,模板元,編程

編譯期數值計算

第一個 C++ 模板元程序是 Erwin Unruh 在 1994 年寫的,這個程序計算小于給定數 N 的全部素數(又叫質數),程序并不運行(都不能通過編譯),而是讓編譯器在錯誤信息中顯示結果(直觀展現了是編譯期計算結果,C++ 模板元編程不是設計的功能,更像是在戲弄編譯器,當然 C++11 有所改變,下面以求和為例講解 C++ 模板編譯期數值計算的原理:

#include <iostream>  template<int N> class Sumt { public:   static const int ret = Sumt<N - 1>::ret + N; };  template<> class Sumt<0> { public:   static const int ret = 0; };  int main() {   std::cout << Sumt<5>::ret << '/n';   return 0; }

當編譯器遇到 sumt<5> 時,試圖實例化之,sumt<5> 引用了 sumt<5-1> 即 sumt<4>,試圖實例化 sumt<4>,以此類推,直到 sumt<0>,sumt<0> 匹配模板特例,sumt<0>::ret 為 0,sumt<1>::ret 為 sumt<0>::ret+1 為 1,以此類推,sumt<5>::ret 為 15。值得一提的是,雖然對用戶來說程序只是輸出了一個編譯期常量 sumt<5>::ret,但在背后,編譯器其實至少處理了 sumt<0> 到 sumt<5> 共 6 個類型。

從這個例子我們也可以窺探 C++ 模板元編程的函數式編程范型,對比結構化求和程序:for(i=0,sum=0; i<=N; ++i) sum+=i; 用逐步改變存儲(即變量 sum)的方式來對計算過程進行編程,模板元程序沒有可變的存儲(都是編譯期常量,是不可變的變量),要表達求和過程就要用很多個常量:sumt<0>::ret,sumt<1>::ret,…,sumt<5>::ret 。函數式編程看上去似乎效率低下(因為它和數學接近,而不是和硬件工作方式接近),但有自己的優勢:描述問題更加簡潔清晰(前提是熟悉這種方式),沒有可變的變量就沒有數據依賴,方便進行并行化。

模板實現的條件 if 和 while  :

template<bool c, typename Then, typename Else> class IF_ { };  template<typename Then, typename Else> class IF_<true, Then, Else> { public:   typedef Then reType; };  template<typename Then, typename Else> class IF_<false, Then, Else> { public:   typedef Else reType; };  // 隱含要求: Condition 返回值 ret,Statement 有類型 Next template<template<typename> class Condition, typename Statement> class WHILE_ {   template<typename Statement_>   class STOP {   public:     typedef Statement_ reType;   };  public:   typedef typename   IF_<Condition<Statement>::ret,       WHILE_<Condition, typename Statement::Next>,       STOP<Statement>>::reType::reType       reType; }; 

模板循環展開  

模板元編程實現的循環展開能夠達到和手動循環展開相近的性能(90% 以上),并且性能是循環版本的 2 倍多(如果扣除 memcpy 函數占據的部分加速比將更高,根據 Amdahl 定律)。這里可能有人會想,既然循環次數固定,為什么不直接手動循環展開呢,難道就為了使用模板嗎?當然不是,有時候循環次數確實是編譯期固定值,但對用戶并不是固定的,比如要實現數學上向量計算的類,因為可能是 2、3、4 維,所以寫成模板,把維度作為 int 型模板參數,這時因為不知道具體是幾維的也就不得不用循環,不過因為維度信息在模板實例化時是編譯期常量且較小,所以編譯器很可能在代碼優化時進行循環展開。

我們說過模板元編程實際上就是一些復雜的模板,雖然可以把一些復雜的運算提前到編譯器但是代碼閱讀性極差,如果你不是寫一些通用的大型的c++庫為了提高關鍵代碼的性能,千萬要適可而止,要不然止小心被打。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
深夜福利日韩在线看| 亚洲人成网在线播放| 国产精品你懂得| 91国自产精品中文字幕亚洲| 亚洲男女自偷自拍图片另类| 久久噜噜噜精品国产亚洲综合| 国产精品一区二区三区在线播放| 欧美极品少妇xxxxx| 国产一区二区三区在线免费观看| 久久久久久久久爱| 欧美国产日本在线| 亚洲人成网站免费播放| 亚洲va国产va天堂va久久| 国内精品久久久久影院优| 中文欧美日本在线资源| 中文字幕亚洲一区二区三区五十路| 亚洲影院高清在线| 欧美日韩国产综合新一区| 国产精品入口福利| 亚洲大尺度美女在线| 97在线免费观看视频| 欧美日韩国产页| 欧美猛少妇色xxxxx| 日韩电影在线观看中文字幕| 亚洲自拍中文字幕| 欧美大片网站在线观看| 欧美小视频在线观看| 国产一区二区在线播放| 国产精品v日韩精品| 日韩经典中文字幕| 91精品国产自产在线老师啪| 欧美影院久久久| 国产精品中文字幕在线| 日本欧美在线视频| 日韩在线观看av| 亚洲级视频在线观看免费1级| 欧美放荡办公室videos4k| 亚洲一区二区中文| 国产91成人video| 中文字幕日韩av电影| 欧美在线xxx| 亚洲激情视频网| 亚洲精品久久久一区二区三区| 最近2019年好看中文字幕视频| 日本高清视频精品| 伊人伊人伊人久久| 成人性生交大片免费看视频直播| 日韩美女主播视频| 日韩在线小视频| xxxxx成人.com| 精品一区二区三区四区| 国产aaa精品| 少妇高潮久久久久久潘金莲| 26uuu日韩精品一区二区| 69视频在线免费观看| 日韩小视频网址| 久久99精品久久久久久噜噜| 国产精品久久久久一区二区| 精品国产福利在线| 最新中文字幕亚洲| 欧美成人精品在线观看| 国内精久久久久久久久久人| 91久久中文字幕| 97视频免费观看| 国产亚洲欧美日韩美女| 亚洲欧美一区二区三区在线| 国产一区二区三区在线观看视频| 亚洲精品日韩激情在线电影| 亚洲人永久免费| 成人久久18免费网站图片| 91久久精品久久国产性色也91| 国语自产精品视频在线看一大j8| 国产精品美女视频网站| 久久综合伊人77777尤物| 日韩欧美亚洲一二三区| 亚洲电影av在线| 日韩成人av网| 在线播放日韩精品| 欧美在线视频a| 亚洲国产精彩中文乱码av在线播放| 久久国内精品一国内精品| 国产精品久久久久久久久久免费| 亚洲视频777| 免费91在线视频| 韩国v欧美v日本v亚洲| 亚洲第一视频在线观看| 欧美激情欧美激情在线五月| 欧美视频在线观看 亚洲欧| 国产精品高清免费在线观看| 国产成+人+综合+亚洲欧洲| 97香蕉超级碰碰久久免费的优势| 91精品在线影院| 成人深夜直播免费观看| 亚洲综合小说区| 国产精品欧美亚洲777777| 91精品视频免费观看| 亚洲国产成人精品一区二区| 欧美插天视频在线播放| 久久久久久久999精品视频| 亚洲精品电影在线观看| 91亚洲国产成人精品性色| 中文字幕欧美日韩va免费视频| 精品国产欧美一区二区三区成人| 亚洲的天堂在线中文字幕| 91在线免费视频| 在线观看久久久久久| 狠狠躁18三区二区一区| 国产精品一区二区女厕厕| 2019国产精品自在线拍国产不卡| 伦伦影院午夜日韩欧美限制| 欧美中文字幕第一页| 日韩二区三区在线| 亚洲国产精品国自产拍av秋霞| 亚洲男人天堂九九视频| 欧美成人在线网站| 国产精品视频久久久久| 国产99视频在线观看| 久久精品国产成人| 日韩av一区二区在线| 亚洲欧美成人一区二区在线电影| 久久99精品视频一区97| 国产日韩精品综合网站| 日韩大胆人体377p| 亚洲电影在线观看| 欧美日韩国产一区二区| 国产91热爆ts人妖在线| 国产精品久久久久av免费| 日韩av在线免费观看| 日韩av在线免费观看| 欧美日韩高清在线观看| 亚洲日韩欧美视频| 国产精品三级网站| 黑人精品xxx一区| 国产自产女人91一区在线观看| 国产精品久久久久久一区二区| 96国产粉嫩美女| 亚洲一区二区三区sesese| 成人在线观看视频网站| 91久久精品日日躁夜夜躁国产| 国产久一一精品| 日韩中文字幕在线免费观看| 亚洲激情视频网站| 在线播放精品一区二区三区| 国产精品久久97| 国产成人精品综合久久久| 欧美日韩一区二区精品| 91精品视频大全| 国产精品精品视频| 国产亚洲福利一区| 久久精品亚洲94久久精品| 欧美激情免费视频| 欧美日本亚洲视频| 爱福利视频一区| 97视频免费在线观看| 狠狠色狠狠色综合日日小说| 国产v综合v亚洲欧美久久| 亚洲欧美日韩在线高清直播| 国产成人精彩在线视频九色| 精品国产一区久久久| 国产亚洲欧美日韩一区二区| 美女精品久久久| 国产精品自拍偷拍| 亚洲成在人线av| 亚洲国产精品女人久久久|