C++:非类型模板参数,模板的特化与偏特化

标题

    • 非类型模板参数
    • 模板的特化
      • 特化的原因:
        • 函数模板的特化
      • 类模板的特化
        • 全特化
        • 偏特化(重点)
    • 模板的分离编译
    • 模板总结

在模板参数列表中,实际上是将用户存储元素的类型参数化
在写代码时不用关心类型,T就是将具体类型参数化,将T这种参数称为类型参数

非类型模板参数

模板的参数类型分为两种:函数模板,类模板

  • 在定义模板参数列表时,除了给类型参数外,还能用系统提供的内置类型作为模板参数
  • 就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用

C++:非类型模板参数,模板的特化与偏特化_第1张图片

注意:

  • 非类型模板参数N为常量,N值是不能修改的
  • 浮点数、类对象以及字符串是不允许作为非类型模板参数
  • 非类型的模板参数必须在编译时就应确认结果;也就是说在编译阶段就应确定非模板参数的值,而不是程序运行起来后才知道此处的值
  • 因为模板要在编译阶段确定所有可能的值
    也就是说实例化时,非模板参数必须是常量或者是常量表达式

模板的特化

函数模板的特化就是对模板进行特殊化处理
模板的特化就是实例化模板里的参数,并且重新写一种方法

特化的原因:

为了处理一些特殊类型,例如字符串的大小比较

  • 字符串在比较时有自己特定的比较规则,不是按字符串的比较规则比较,而是按地址大小比较的;
  • 因为字符指针在传参时传的是地址,所以比较结果错误;
  • 所以对模板进行特化,就是为了处理一些特殊类型;

C++:非类型模板参数,模板的特化与偏特化_第2张图片

函数模板的特化

就是对模板进行特殊化处理,模板的特化就是实例化模板里的参数,并且重新写一种方法

C++:非类型模板参数,模板的特化与偏特化_第3张图片

  • 对于函数模板来说,如果哪种类型处理不了,一般情况下是不对模板进行特化,而是写一个和名字一样的普通函数处理
  • 一般不用对函数模板进行特化,因为会出现很多问题,就算语法正确通过编译,最后编译器也不一定调用

类模板的特化

全特化

类模板有两个类型参数,T1、T2;将模板参数列表中所有的参数都具体化
C++:非类型模板参数,模板的特化与偏特化_第4张图片

偏特化(重点)

方式1:部分特化,将一部分参数特化,相对于全特化来说

C++:非类型模板参数,模板的特化与偏特化_第5张图片

方式2:对参数类型限制的更加具体,(将类型参数限制的更加具体)
C++:非类型模板参数,模板的特化与偏特化_第6张图片

模板的分离编译

模板不支持源文件和头文件分离定义

  • 将模板的声明和定义分开后,在主函数调用模板实例化会报错;
  • 而在模板的源文件中进行实例化(也就是在temp.cpp中实例化一次后),再次编译后才正确;

C++:非类型模板参数,模板的特化与偏特化_第7张图片

  • 这是因为在模板的源文件中,只要有实例化就会生成相应的函数,在temp.cpp中没有实例化,就没有相应的函数生成;
  • 编译阶段,如果某个源文件中没有函数的实现,编译器会认为这些函数在其它源文件中实现了;
  • 链接阶段,编译器才寻找各源文件中使用确未在源文件下实现的函数;
  • 未找到则报链接错误

模板的编译与正常的编译不同,模板的编译分为两个阶段:

  • 实例化前:编译器只对模板进行一些简单的语法检测(只检测模板参数列表,不检查模板体);
  • 实例化后:根据实例化结果,来确定模板参数列表中参数的实际类型,然后生成代码并对代码编译;

解决方法:

  1. 在模板的源文件中进行实例化;
  2. 只需要将模板源文件的后缀改为.hpp,然后在该文件下实现模板即可,使用时包含其.hpp文件即可

模板总结

优点
1.模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
2.增强了代码的灵活性

缺陷
1.模板会导致代码膨胀问题,也会导致编译时间变长
2.出现模板编译错误时,错误信息非常凌乱,不易定位错误

你可能感兴趣的:(C++,c++)