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

模板的进阶
非类模板参数
类模板的特化
静态数组: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;
}