zoukankan      html  css  js  c++  java
  • 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。而是电脑运缓慢....

  • 相关阅读:
    NGBOSS转型在即:COTS初露锋芒
    [原]CmsEasy安装,后台“内容管理”页面空白
    CentOS5安装mcrypt问题
    [转]Grub安装修复
    [转]BOSS3接近尾声
    多渠道整合开启NGBOSS第一步
    [原][转]TUXEDO与ORACLE数据库的互连
    [译]Oracle Data Cartridge| Oracle数据筒介绍
    [译]ORACLE数据弹药桶(Data Cartridge)简介
    [原]再说精度用于显示的数字出现精度问题的处理(Perl/Java)
  • 原文地址:https://www.cnblogs.com/gongxijun/p/4385838.html
Copyright © 2011-2022 走看看