模板的进阶 非类模板参数 类模板的特化

模板的进阶
非类模板参数
类模板的特化
静态数组:array:template < class T, size_t N > class array; array为可以存放N个元素的数组模拟实现:
#include<iostream>
using namespace std;
namespace bit{
template < class T, size_t N > ;
class array{
    public:
    private:
        //T类型参数,N非类型参数
        T array[N];   
    };
}
 
int main(){
    bit::array<int,10> a;
    return 0;
}
 
    模板---->任意类型都可以处理
    特化---->对模板不能处理或者处理有误的类型进行特殊化处理(比如对于char *类型,是一个字符串,比较时应该通过字符串的方法进行比较,但是通过这个模板进行比较时直接用大于小于><进行比较,所以需要对模板进行特化)
        1.必须提供一个类模板(对于函数模板,一般不进行特化)
        
template<class T>
T& Max(T& a,T& b){
    return a>b?a:b;
}
template<>
char *& Max<char *>(char *& left,char *& right){
    //不能加const,否则会出错,报错:不是函数模板的专用化
    //加了之后对于特化的成本增加了
    //如果处理不了,直接给出这种处理的函数即可,不需要特化
    if(strcmp(left,right)>0){
        return left;
    }
    retrun right;
}
 
int main(){
    int a=0;
    int b=3;
    cout<<Max(a,b)<<endl;
    char *p1="hello";
    char *p2="world";
    cout<<Max(p1,p2)<<endl;
    return 0;
}
 
类模板的特化:
    1.全特化:类模板实例化期间将类型全给出来比如:class Data<int , double>
    2.偏特化(1)部分特化:class Data<int ,T>
                   (2)   让模板的参数列表中的类型参数限制更加严格class Data<T*,T*>
应用场景:识别被拷贝的元素的类型是内置类型还是用户自定义类型?
                内置类型:不会涉及资源的管理
                自定义类型:会涉及类型的管理
    类型萃取:
        
//实现通用的拷贝函数:
template<>
                                              
//内置类型
struct TypeTraits<char>{
    typedef TrueType POD_TYPE;
};
 
template<>
struct TypeTraits<double>{
    typedef TrueType POD_TYPE;
};
 
struct TypeTraits<int>{
    typedef TrueType POD_TYPE;
};
 
template<>
struct TypeTraits<float>{
    typedef TrueType POD_TYPE;
};
                                             
//是实现的通用的类型,进而判断是内置类型还是自定义类型
                                             
 
template<>
struct TypeTraits<T>{
    typedef FalseType POD_TYPE;
};
                                           
 
struct TrueType{
    static bool Get(){
        return true;
    }
};// 代表内置类型
 
struct FalseType{
    static bool Get(){
        return false;
    }
};// 代表自定义类型
 
    
template<class T>
void Copy(T* dst,T* src,size_t size){
    if(TypeTraits<T>::POD_TYPE::Get()){
        memset(dst,src,sizeof(T)*size);
    }
    else{
        for(i=0;i<size;++i){
            dst[i]=src[i];
        }
}

模板的分离编译:
    预处理阶段---->编译---->汇编---->链接---->可执行程序
    1.预处理 宏替换,宏展开,删除注释,包含头文件
    2.编译:语法分析(语法树—>中序遍历),语义分析,词法分析(扫描),代码优化;编译器只编译当前工程的所有源文件,头文件不参与编译(?????),头文件已经展开了。对于当前工程的所有源文件,分别单独编译,分别生成目标文件
 
    1.对模板进行简单的语法检测
    2.生成代码-->前提(实例化)
        未解决的符号表
            编译期间生成未解决的符号表,链接期间进行解决(链接期间到别的已解决的符号表中去找,如果没找到则报错:无法解析的外部符号;如果找到了,则解决了该问题(地址问题))
        已解决的符号表
 

模板的分离编译:
    解决这种问题通过建立全新的"头文件"“.hpp”,相当于将头文件和源文件合并到一块了
推荐方法:
//a.hpp
template<class T,class T>
T& Add(T& left, T& right){
    return left+right;
}
//.cpp
#include"a.hpp"
int main(){
    Add(1,2);
    Add(1.0,3.0);
    return 0;
}
另一种方法(不推荐)
a.cpp:
T& Add(T& left,T& right){
    return left+right;
}
void testFun(){
    这种方法是通过下面代码进行模板的实例化,生成相应的函数,如果不给出实例化,由于每个源文件是单独编译的,因此对于test.cpp源文件中的Add(1,2)会生成未决符号表,在链接期间没有找到相应的函数,所以会报错:无法识别的外部符号
    Add(2,1);
    Add(2.0,1.0);
}
a.h
template<class T,class T>
T& Add(T& left,T& right);
 
test.cpp:
#include"a.h"
int main(){
    Add(2,1);
    Add(2.0,1.0);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/love-you1314/p/10367276.html