【初识C++】5.模板详解

模板简单介绍

模板是C++基于C语言的
优点:
1.复用代码,更快的迭代开发,让脏活累活由编译器来完成
2.模板让我们的代码更加的灵活
缺点:
1.看起来节省了代码。但是编译后还是存在代码膨胀的问题
2.模板出现错误之后,有时报错混乱且不准确。有时不容易定位错误位置
3.模板不支持分离编译

模板的全特化

小测试:比较a, b变量的大小

//1.编写一个模板函数
template<class T>
bool Less(T left, T right)
{
  return left < right;
}
int main()
{
//使用上述模板函数进行测试
  int b = 20; 
  int a = 10;
  cout << Less(a, b) << endl;
  cout << Less(&a, &b) << endl;

  return 0;
}


//查看运行结果
[clx@VM-20-6-centos inherit_C++]$ ./test
1
0

结论:我们发现因为栈是由上向下增长的,所以a的地址大于b的地址。我们的本意是比较a,b变量的大小,但是第二次比较显然并没达到目的,所以我们需要对特殊的例子进行特化处理,使函数达到目的

解决方案

方法一:直接构造特例函数
bool Less(int* left, int* right)
{
   return *left < *right;
}
//因为编译器遇到函数首先去找是否存在已经匹配的函数,所以直接写一个现成的,编译器就不会根据模板自动生成

方法二:函数模板特化
template<>      
bool Less<int*>(int* left, int* right)      
{      
  return *left < *right;        
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 

当模板的所有参数都已经规定好了,这样的特化叫做全特化。若部分确定,则为偏特化

模板的偏特化

普通偏特化

template<class T1, class T2>           //Data类有两个模板参数
class Data     
{    
  public:    
    Data()    
    {    
      cout << "Data<T1, T2>" << endl;    
    }    
  private:    
    T1 _d1;    
    T2 _d2;    
};    
    
template<class T>  
class Data<T, char>                    //Data类的偏特化,只设置一个模板参数
{  
  public:  
    Data()  
    {  
      cout << "Data<T, char>" << endl;  
    }  
  private:  
    T _d1;                                                                                                                                                                              
    char _d2;  
};  

int main()
{
  Data<int, char> d1;                   //实例化时若第二个参数为char则调用偏特化模板
  Data<int, int> d2;
  return 0;
}

[clx@VM-20-6-centos inherit_C++]$ ./test
Data<T, char>
Data<T1, T2>

特殊偏特化
偏特化的模板参数数量并非一定小于模板的参数数量

template<class T1, class T2>    
class Data<T1*, T2*>                        //若参数类型是指针的话就会调用此模板
{    
  public:    
    Data()    
    {    
      cout << "Data<T1*, T2*>" << endl;    
    }    
  private:    
    T1* _d1;    
    T1* _d2;    
};    

int main()
{
   Data<int*, char*> d;
   return 0;
}

[clx@VM-20-6-centos inherit_C++]$ ./test
Data<T1*, T2*>

此处模板参数使用的是指针, 当然模板参数如果是引用也可以识别

小结:特化是对参数的进一步限制

非类型模板参数特化

template<size_t N>
class Te
{
  public:
    Te()
    {
      cout << "Te<size_t N>" << endl;
    }
};

template<>
class Te<1000>              
{
  public:
    Te()
    {
      cout << "Te<1000>" << endl;
    }
};
int main()
{
  Te<1> t1;
  Te<1000> t2;
  return 0;
}

[clx@VM-20-6-centos inherit_C++]$ ./test
Te<size_t N>
Te<1000>

模板的分离编译

模板不支持分离编译,即使用.h和.cpp分别声明和定义模,模板声明定义合在一个文件中
分离编译的价值:便于维护,.h文件便于了解框架设计和基本功能, .cpp 了解具体实现细节
为什么模板不支持分离编译呢?这得从可执行程序生成的过程来解释

首先我们先了解一下一个可执行程序生成的几个步骤,并且此程序由pro.cpp, pro.h, test.cpp组成

1.预处理:头文件展开/宏替换/删除注释/条件编译
2.编译: 检查语法错误, 没有问题生成汇编代码
3.汇编: 将汇编转化成机器码
4.链接: 将函数地址填入

普通函数或类
编译阶段test.cpp文件中包含函数声明和调用,声明告诉编译器存在此函数,请链接的时候去找。pro.cpp文件中包含函数的定义和声明,编译器将函数定义转换成汇编代码,并且生成一个函数表存储此文件中函数的地址(各函数生成第一条汇编代码的地址)。
在链接阶段,test.cpp生成的汇编代码从pro.cpp生成的函数表中获取函数地址,填入自己的代码当中,这样就生成了一份可执行程序

模板函数或类
编译阶段test.cpp文件中包含模板实例化的类型信息以及模板声明。但是因为并没有模板的定义,所以编译器并不知道应该怎么样实例化函数模板,但是因为拥有声明,编译器认为函数体在其他地方,链接时去找。在pro.cpp文件中,有函数的声明和定义,但是其并不知道模板的实例化类型信息,无法推测类型信息也就无法生成正确的函数汇编代码和函数表。
在链接阶段,test.cpp文件去找pro.cpp文件函数表中查找地址,但pro.cpp没有实例化信息无法生成函数,更无法生成函数地址。所以就会产生链接错误

如何解决:

方法一:当模板的声明定义在同一个文件中 pro.hpp test.cpp
因为test.cpp 中引用了pro.hpp作为头文件,在预处理时展开。这样这个文件中就有了函数或类的定义,声明,实例化信息。编译器就可以通过实例化信息来实例化函数或类,实例化的函数就可以生成正确的汇编代码和地址

方法二:显示实例化(有缺陷)

template
void Print<double>(const int& m){};  

缺陷:用一个就得显示实例化一个,失去了模板的价值,非常麻烦不,推荐使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白在进击

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值