C++ 模板与泛型编程

模板与泛型编程

为了能更方便的使用STL模板库,先行了解模板与泛型编程的语法和思想

​ 模板就是泛型编程,为了编写更加通用的程序代码,实现算法与类分离————>代码复用

也即编写更加抽象的类和函数

函数模板
template<typename T>
返回值类型 函数名(参数列表){
    函数体;
}
//template是模板关键字<模板类型参数>
//typename可以用class替换;
//模板类型参数可以有很多,不是具体的类型
//每一个模板参数都需要用", "隔开
函数模板实例化—>模板函数
  • 实例化后变为模板函数:函数模板需要用具体的类型实例化
    • 使用:函数模板名<类型参数列表> (实参列表)
自动类型推导
  • 某些支持自动类型推导

    • 使用时传递了实参,根据实参类型进行推导,

      但有些情况可能产生二义性,此时需要提供<类型参数>

  • 某些不支持

    template<typename T,size_t CAP>
    void func(){//模板没有参数列表
    	cout << typeid(T).name() << endl;
    	cout << CAP << endl;
    }
    
    
    int main(int argc,char *argv[]){
    	func();//没有实例化类型
        return 0;
    }
    
    • 模板没有参数列表
    • 多种类型
    • 没有实例化类型
函数模板特化

针对某些特殊的类型(C风格的字符串),通用的模板可能不适用

需要针对该类型写一个特化的函数(但此前须有通用版本才能称为特化)

template<> 返回值类型 函数名(参数列表){
    函数体;
}
函数模板支持非类型参数
//c++11
template<unsigned N,unsigned M>
int compare(const char (&p1)[N],const char (&p2)[M]){
	cout << N << "," << M << endl;
	return strcmp(p1,p2);
}

int main(int argc,char *argv[]){
	int ret = compare("Hello","hi");
	cout << ret << endl;
	int a = 6,b = 3;
	compare<6,3>("Hello","hi");
	//compare<a,b>("Hello","hi");
	const int x = 6, y = 3;
	compare<x,y>("Hello","hi");
	char s1[] = "Hello";
	char s2[] = "hi";
	const int m = strlen(s1)+1,n = strlen(s2)+1;
	//compare<m,n>("Hello","hi");
    return 0;
}

在对非类型模板参数实例化时,只能用常量或者常量表达式

模板编译

当编译器遇到一个模板定义时, 它并不生成代码,只有当实例化出模板的一个特定版本时, 编译器才会生成代码,所以模板会二次编译,一次编译检查模板本身的语法, 第二次是模板实例化后,生成特定的版本和类进行编译

在多文件编程中,函数和类的声名放在头文件中,函数和类的实现放在文件中.cpp

但是模板的声名和定义是不能放在不同的文件中,因为如果只包含声名,在实例化时,将无法得到模板的定义,所以模板编程中会把模板的声名和定义直接放在头文件中

编译错误报告
  1. 编译模板代码,针对模板本身进行语法检查,需要代码满足模板规则

  2. 使用模板实例时,检查实例化时模板参数的个数是否相等 ,类型是否匹配

  3. 模板实例化,根据模板用具体的实例化,生成具体的模板函数或者模板类

    • 再次编译模板函数和模板类,进行语法检查,之哦于在这个阶段才能发现类类型的问题(如:不支持的类型,没有连接到函数)
普通函数和模板函数同名

如果普通函数和模板函数除了函数体外完全一致时, 会优先调用普通函数,如果像调用函数模板,则需要显示类型实例化,函数模板中针对类型特化的版本,则调用特化的版本。

template<typename T>
void func(T a){}
tmeplate<>
void func(int a){}
void func(int a){}

func(10);//普通
func<int>(10);//特化
func('a');//通用
尾置返回类型
template<typename T>
auto maxarr(T beg, T end)->decltype(*beg){
    
}
类模板
#include <iostream>
#include <cstring>
using namespace std;
//通用的类模板
template<typename T>
class Compare{
public:
	Compare(const T& a,const T& b):a(a),b(b){
		cout << "通用版本" << endl;	
	}

	T max(void){
		return a<b?b:a;
	}

	T min(void){
		return a<b?a:b;
	}

	T getFirst(){
		return a;
	}
	T getSecond(){
		return b;
	}
private:
	T a;
	T b;
};
//成员特化
template<> char* Compare<char *>::max(){
	cout << "成员特化" << endl;
	return strcmp(a,b)<0?b:a;
}

template<> char *Compare<char *>::min(){
	cout << "成员特化" << endl;
	return strcmp(a,b)<0?a:b;
}


//全员特化版本
template<>
class Compare<const char *>{
public:
	Compare(const char * const & a,const char * const & b):a(a),b(b){
		cout << "特化" << endl;	
	}
	const char *max(void){
		return strcmp(a,b)<0?b:a;
	}
	const char *min(void){
		return strcmp(a,b)<0?a:b;
	}
	const char *getFirst(){
		return a;
	}
	const char *getSecond(){
		return b;
	}
private:
	const char *a;
	const char *b;
};

int main(int argc,char *argv[]){
	Compare<int> c(1,3);//无法进行隐式类型推导
	cout << c.max() << endl;
	cout << c.min() << endl;
	Compare<const char *> c1("Hello","hello");
	cout << c1.max() << endl;
	cout << c1.min() << endl;
	char s1[10] = "hello";
	char s2[10] = "Hello";
	Compare<char *> c2(s1,s2);
	cout << c2.max() << endl;
	cout << c2.min() << endl;
    return 0;
}

  • 类模板无法进行自动类型推导
针对特殊类型进行全员特化
  • 类所有的属性和方法重写

    template<>
    class 类模板名<特化的类型>{
        
    }
    
针对特殊类型进行成员特化
  • 只针对几个函数特化

    template<>返回值类型 类模板名<特化的类型>::成员方法名(参数列表){
        
    }
    
针对特殊类型进行偏特化
#include <iostream>
using namespace std;

template<typename T>
class C{
public:
	C(){
		cout << "T" << endl;
	}
};
//针对数组的偏特化
template<typename T>
class C<T[]>{
public:
	C(){
		cout << "T[]" << endl;
	}
};
//针对指针的偏特化
template<typename T>
class C<T*>{
public:
	C(){
		cout << "T*" << endl;
	}
};

template<typename T1,typename T2,typename T3>
class A{
public:
	A(){
		cout << "T1,T2,T3" << endl;
	}				
};

template<typename T1,typename T2>
class A<T1,T2,T2>{
public:
	A(){
		cout << "T1,T2,T2" << endl;
	}
};

template<typename T1>
class A<T1,T1,T1>{
public:
	A(){
		cout << "T1,T1,T1" << endl;
	}
};

template<typename T1>
class A<T1,T1[],T1[]>{
public:
	A(){
		cout << "T1,T2[],T2[]" << endl;
	}
};

template<typename T1>
class A<T1*,T1*,T1*>{//针对指针的偏特化
public:
	A(){
		cout << "T1*,T1*,T1*" << endl;
	}	
};

template<typename T1>
class A<T1[],T1[],T1[]>{//针对三个类型相同情况下的偏特化
public:
	A(){
		cout << "T1[],T1[],T1[]" << endl;
	}	
};


int main(int argc,char *argv[]){
	C<int> c1;
	C<int[]> c2;
	C<int*> c3;
	A<int,double,string> a1;
	A<int,string,string> a2;
	A<int,int,int> a3;
	A<int,int[],int[]> a4;
	A<int*,int*,int*> a5;
	A<int[],int[],int[]> a6;
    return 0;
}

  • 针对指针或者数组类型的偏特化,或者针对类型本身特殊情况的特化
  • 在实例化时会选择特化程度更高的实例化
类模板允许非类型参数

非类型参数在实例化时必须是常量或者常量表达式

类模板允许缺省值

缺省模板参数需要满足靠右原则

函数模板在C++11以后也允许有模板缺省参数

普通类中含有模板成员方法
可变长类型模板参数
void func(){
    
}

template<typename t,typename ...Args>
void func(const T& t,const Args& ...args){
    //cout << t << " " << endl;
    func(args...);//func()
}

template<typename T>
class X{
    template<typename ... Args>
    void emplace(iterator pos,Args&& ...args){
        
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值