模板——从低级到进阶

打印 上一主题 下一主题

主题 518|帖子 518|积分 1554

目录
媒介:
一、非类型模板参数
二、模板的特化 
        2.1 函数模板特化
        2.2 类模板特化
                        2.2.1 全特化
                2.2.2 偏特化
三、模板分离编译
        3.1 什么是分离编译
        3.2 模板的分离编译  
四、模板总结


媒介:

        我们前面已经对初阶模板有了比较深刻的了解,各人如果忘记,可前往进行复习:CSDN
接下来,我们一起来学习更加深刻的内容吧。
一、非类型模板参数

        什么是模板参数呢?模板参数是指在利用模板时通报给模板的参数,用来指定模板的具体类型或值。模板参数可以是类型、常量或模板本身。
           模板参数又分别为:类型模板参数非类型模板参数
          类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称
          非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来利用。
          对于类型模板参数,没什么好说的,那么咱们接下来来了解非类型模板参数。
        对于非类型模板参数的利用,与类型模板参数雷同,就是模板参数多了一个常量,以类模板为例如下:
  1. template <typename T, int N>
  2. class MyClass {
  3.     //
  4. };
复制代码
        各人以为,非类型模板参数有什么应用的场景呢?
        我们可不可以运用该特点,来开辟出,类模板静态数组,如下:
  1. template<class T,size_t N = 2>
  2. class array
  3. {
  4. private:
  5.         T _a[N];
  6. };
  7. int main()
  8. {
  9.         array<int, 2>a1;
  10.         array<double, 20>a2;
  11.         return 0;
  12. }
复制代码
        我们可调试来看看是否和我们想的一致:

         我们看到完全和我们想的一致。不外,我们留意一点:非类型模板参数是一个常量,这时我们不能对其赋值,否则会编译报错。
        

        别的我们留意以下几点:
           1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
          2. 非类型的模板参数必须在编译期就能确认结果。 
  二、模板的特化 

        关于模板特化,我们首先就要知道,在怎样的景象下必要模板特化,以下面函数模板为例:
  1. template<class T>
  2. bool Less(T left,T right)
  3. {
  4.         return left < right;
  5. }
复制代码
        这个函数在绝大多数的情况下都恰当,但是,各人留意看这组测试用例:
  1. int main()
  2. {
  3.         int* p1 = new int[1];
  4.         int* p2 = new int[1];
  5.         *p1 = 1;
  6.         *p2 = 2;
  7.         cout << Less(p1, p2) << endl;
  8.         return 0;
  9. }
复制代码
        运行结果如下:

        我们可以看到两次运行结果大不雷同,这时为什么呢?原来,这是按照所开辟地点的地点大小进行比较,所以无外乎出现忽高忽低的情况。 
        那么,我们该如那里理该情况呢?那就指向主题了——模板特化。
           模板特化是一种定制模板的方法,通过为特定的模板参数提供特定的实现来满意不同的需求。可以通过类模板特化函数模板特化来为特定类型或参数提供特定的逻辑。模板特化可以用于解决特殊处理需求,提供更准确的实现。
          2.1 函数模板特化

                函数模板特化步调如下:
                   1. 必须要先有一个基础的函数模板
                  2. 关键字template后面接一对空的尖括号<>
                  3. 函数名后跟一对尖括号,尖括号中指定必要特化的类型
                  4. 函数形参表: 必须要和模板函数的基础参数类型完全雷同,如果不同编译器大概会报一些希奇的错误。
                  对于上述模板,我们可做出以下的特化:
  1. template<>
  2. bool Less<int*>(int* left, int* right)
  3. {
  4.         return *left < *right;
  5. }
复制代码
                这样我们便可得到正确的运行结果。
                这里我们要留意这样一点:一样平常情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给出。如下:
  1. bool Less(int* left, int* right)
  2. {
  3.         return *left < *right;
  4. }
复制代码
        2.2 类模板特化

                类模板特化分为:全特化偏特化。
                        2.2.1 全特化

                                全特化即是将模板参数列表中所有的参数都确定化。
  1. template<class T1, class T2>
  2. class Data
  3. {
  4. public:
  5.         Data()
  6.         {
  7.                 cout << "Data<T1, T2>" << endl;
  8.         }
  9. private:
  10.         T1 _d1;
  11.         T2 _d2;
  12. };
  13. template<>
  14. class Data<int, char>
  15. {
  16. public:
  17.         Data()
  18.         {
  19.                 cout << "Data<int, char>" << endl;
  20.         }
  21. private:
  22.         int _d1;
  23.         char _d2;
  24. };
  25. void TestVector()
  26. {
  27.         Data<int, int> d1;
  28.         Data<int, char> d2;
  29. }
复制代码
                2.2.2 偏特化

                        偏特化:任何针对模版参数进一步进行条件限定计划的特化版本。
                           偏特化有以下两种形式:
                          1. 部分特化 将模板参数类表中的一部分参数特化。
                          2.参数更进一步的限定 偏特化并不但仅是指特化部分参数,而是针对模板参数更进一步的条件限定所计划出来的一个特化版本。
  1. template<class T1>
  2. class Data<T1, int>                                //部分特化        这种方式下,模板类的某些模板参数被特化,而其他模板参数保持不变。
  3. {
  4.         //........
  5. };
  6. template<class T1,class T2>                //参数更进一步的限制   偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。
  7. class Data<T1*, T2*>
  8. {
  9.         //........
  10. };
复制代码
                 留意:类模板偏特化不能重载函数,也不能包含成员函数外的非类型成员,否则会导致编译错误。
三、模板分离编译

        3.1 什么是分离编译

                   一个程序(项目)由多少个源文件共同实现,而每个源文件单独编译生成目标文件,末了将所有目标文件链 接起来形成单一的可实行文件的过程称为分离编译模式。
          3.2 模板的分离编译  

                在我们写代码时,我们会发现:当我们模板分离编译时,编译器会报错,这时为什么呢?
                我们都明白:我们写好代码时,生成可实行程序会经历以下阶段:预处理、编译、汇编、链接。这四大阶段。这里我们简单复习一下:
                   预处理阶段会进行:头文件展开、宏更换、条件编译、去掉注释等操作。生成.i文件
                  编译阶段会进行:语法检查,生成汇编代码等。生成.s文件
                  汇编阶段会进行:汇编代码转化二进制机器码。生成.o文件
                  链接阶段会进行:目标文件合并在一起生成可实行程序,并把必要的函数地点连接上。
                  当模板分离编译时,在编译阶段:我们找不到具体的函数地点,从而会造成编译器报错。
                想解决也很简单,提供两中办法:
                   1. 将声明和定义放到一个文件 "xxx.hpp" 里面或者xxx.h其实也是可以的。保举利用这种。
                  2. 模板定义的位置显式实例化。这种方法不实用,不保举利用。
  四、模板总结

         【优点】
                   1. 模板复用了代码,节省资源,更快的迭代开辟,C++的标准模板库(STL)因此而产生
                  2. 增强了代码的机动性
          【缺陷】
                   1. 模板会导致代码膨胀问题,也会导致编译时间变长
                  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误
          总之,C++模板是一种强大而机动的编程工具,可以资助我们实现泛型编程,并生成高效、通用的代码。对于C++程序员来说,把握模板机制是必不可少的技能之一。 
完! 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南飓风

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表