C++ template的一些高級用法(元編碼,可變參數,仿函數,using使用方法,. C++ 智能指針)


1 .  通用函數可變參數模板

     對於有些時候,我們無法確切的知道,函數的參數個數時,而又不想過多的使用所謂的函數重載,那么就可以效仿下面的例子:

 1 #include<iostream>
 2 #include<Array>
 3 void showall() { return; }
 4 
 5 template <typename R1 ,typename...  Args>
 6 
 7 void showall(R1 var, Args...args) {
 8 
 9     std::cout << var << std::endl;
10     showall(args...);
11 }
12 
13 int main(int argc, char * args[]) {
14 
15     
16     showall(1, 2, 3, 4, 5);
17     showall("gxjun","dadw","dasds");
18     showall(1.0,2.0,3.5);
19     std::cin.get();
20     return 0;
21 }

在游戲開發中,時常會用到這樣的模板,類型不確定,參數的個數不確定,所以需要用一種類似於遞歸的函數來處理。  第一個函數,表示的是在參數為0時,結束。

效果:

2.  如何使用仿函數:

     首先仿函數的定義: ,仿函數也叫函數對象(Function Object, or Functor),定義就是任何可以像函數一樣被調用的對象。一個普通的函數是函數對象,一個函數指針當然也是,廣義上說任何定義了operator()的類對象都可以看作是函數對象。 (找到文檔)

      其實,往直白的地方說,就是一個不是函數但是具有函數功能且用法和函數相同的對象(結構體或者類)。

下面舉個栗子(用結構體實現函數功能):

  

 1 /*關於C++仿函數*/
 2 #include<iostream>
 3 #include<functional>
 4 using namespace std;
 5 using namespace std::placeholders;  
 6 
 7 template <typename R1 , typename R2>
 8 struct  Calc
 9 {
10     void add(R1 a) {
11         cout << a << endl;
12     };
13     void add_1(R1 a, R1 b) {
14         cout << a + b << endl;
15     }  
16 };
17 
18 int main(int argc, char * args[]) {
19 
20     //函數指針
21     void(Calc<int, double>::*fc)(int  a) = &Calc<int, double >::add;
22     // fc(25);
23     //顯然上面的式子比較的麻煩
24     
25     Calc < int, int> calc;
26     auto  fun = bind(&Calc<int, int >::add, &calc, _1);
27     auto  fun_2 = bind(&Calc<int, int >::add_1, &calc, _1,_2);
28     fun(123);
29     fun_2(12,24);
30    cin.get();
31  return 0;
32 }

    對於bind()這個函數,開頭的是地址,函數名,后面的是第一個列子中的Args....不定參數類型、

效果圖為:

   

3. 使用using別名,函數指針,typdef來實現函數的調用

    雖然是寥寥的幾行代碼,但是功能在實際應用中,卻會發揮很大的作用。

 1 //using別名使用用法
 2 #include<iostream>
 3 #include<windows.h>
 4 int calc() {
 5   //當為無參數時,返回0值
 6     return 0;
 7 }
 8 
 9 template <typename R1 ,typename...Args>
10 int calc(R1 a, Args...args) {
11 
12     return a + calc(args...);
13 }
14 
15 int main(int argc , char * args []) {
16 
17     //使用函數指針
18     int(*fun) (int ,int ,int ,int ) = calc;
19     system("echo 使用函數指針實現1~4累加");
20     std::cout << fun(1,2,3,4)<<std::endl;
21    //使用typedef來實現該功能
22     system("echo 使用typedef實現1~4累加");
23      typedef int(*Add)(int, int, int);
24      Add  Gadd = calc;
25      std::cout << Gadd(1, 2, 3) << std::endl;
26     //使用using別名來實現這么個功能
27     system("echo 使用using實現1~4累加");
28     using Func = int(*) (int, int, int, int);
29     Func func = calc;
30     std::cout << func(1, 2, 3, 4) << std::endl;
31     std::cin.get();
32  return 0;
33 }

效果圖: 

  4. C++模板元編程:

          對於模板元編程: 我的理解是,你所要的計算,在編譯的時候,已經處理玩了,只需要在運行的時候輸出結果即可!

    當我們每每學到模板元編程的時候,就會有一個混淆的詞匯出現,噠,看------函數式編程。 到底什么是函數式編程呢?

    建議去看這篇文章,http://www.ruanyifeng.com/blog/2012/04/functional_programming.html  模板元編程用處廣泛,

    我們知道當硬件條件限制的情況下,除了優化算法,還有一種途徑,那就是用模板元編程。 現在就讓我們來看看這個金典的應用吧!

    斐波那契數列的計算......

   

 1 #include<iostream>
 2 #include<time.h>
 3 #include<windows.h>
 4 /*
 5   斐波那契數列
 6    H(1)=H(0)=1;
 7    H(N)= H(N-1)+H(N-2);
 8 */
 9 using namespace std;
10 
11  /* 普通版普通版 */
12  using _int = long  ;    //使用別名
13  
14  _int feibona(_int ac) {
15     if (ac == 0||ac==1)  return 1;
16     return feibona(ac-1) +feibona(ac-2);
17 }
18 
19  /* 使用元編程 完全特化版 方法如下*/
20  template <_int N>
21  struct data {
22      //采用枚舉
23      enum { res = data<N - 1>::res + data<N - 2>::res };
24  };
25 
26 template <>
27 struct data<1> {
28     //采用枚舉
29     enum { res = 1L };
30 };
31 
32 template <>
33 struct data<0> {
34     //采用枚舉
35     enum { res = 1L };
36 };
37 
38 
39 int main(int argc, char * args[]) {
40 
41     time_t  a ,b;
42     a = clock(); //開始記錄時間
43     cout << data<45L>::res << endl;
44     b = clock(); //開始記錄時間
45     system("echo 采用元編程所消耗的時間");
46     cout << (double)(b - a) / CLK_TCK<<"ms"<<endl;
47     a = clock();
48     cout << feibona(45L) << endl;
49     b = clock();
50     system("echo 采用普通的算法所消耗的時間");
51     cout << (double)(b - a) / CLK_TCK << "ms" << endl;
52     cin.get();
53     return 0;
54 }

  兩者相對比的效果圖:

 

5  C++智能指針 ,關於智能指針和普通指針,的幾種行為的對比

 

 1 /*
 2  智能指針:
 3     對於C++而言:        std::auto_ptr<double> ptr(new double);
 4     對於C++11新的智能指針:         std::unique_ptr<double>  ps(new double);
 5     通過下面幾組數據做些一點
 6 */
 7 #include<iostream>
 8 #include<memory>
 9 #include<windows.h>
10 using  namespace std;
11 /*模式一 分配內存地址,而不手動進行回收 */
12 void showp() {
13     system("echo 分配內存地址,而不手動進行回收");
14     for (int i = 0; i < 10000000; i++) {
15           double * p = new double;   //不釋放
16     }
17     cin.get();
18 }
19 /* 模式二,分配地址,並手動進行回收地址 */
20 void showp1() {
21     system("echo 分配地址,並手動進行回收地址");
22     for (int i = 0; i < 10000000; i++) {
23         double * p = new double;   //不釋放
24         delete p;
25     }
26     cin.get();
27 
28 }
29 /*模式三,分配地址,采用c++通用指針*/
30 void showp2() {
31     system("echo 分配地址,采用c++通用指針");
32 
33     for (int i = 0; i < 10000000; i++) {
34         double * p = new double;   //不釋放
35         auto_ptr<double> ps(p);   //采用智能指針,不會多釋放地址,舊版本vc98支持
36     }
37     cin.get();
38 }
39 /* 模式四,分配地址,采用C++11新型指針 */
40 
41 void showp3() {
42 
43     system("echo 分配地址,采用C++11新型指針");
44     for (int i = 0; i < 10000000; i++) {
45         auto_ptr<double> ps(new double);   //采用智能指針,C++11新特性
46     }
47     cin.get();
48 }
49 
50 int main(int argc , char * args []) {
51  
52     //auto_ptr
53    //函數指針
54     void(*p[])() = { showp,showp1,showp2,showp3 };
55     //for (auto data : p) {
56     //    data();
57    //}
58     p[1]();
59     system("echo 按一下結束");
60     cin.get();
61   return 0;
62 }

模式一: 消耗內存截圖

模式二  吃掉的內存截圖:

模式三,吃掉的內存截圖:

模式四,吃掉的內存截圖:

  使用智能指針的好處:

    1 、 不會對一個分配的地址,釋放兩次。如果手動釋放地址,存在着重復釋放或者漏放的情況。 避免內存泄露。

      2.  釋放及時,不會搗鼓電腦中cpu換句話說,不會吃cpu。而是電腦運緩慢....

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM