模板与泛型编程

定义模板


函数模板

  • 下面的两个函数,除了参数类型,其他完全相同
    在这里插入图片描述
  • 如果我们需要不同类型参数的相同函数
  • 我们可以定义一个通用的函数模板,而不是为每个类型都定义一个新的函数

template <typename T> // 将typename改为class也是可以的 
int compare(const T &v1, const T &v2)
{
	if(v1 < v2) retunrn -1;
	if(v1 < v2) retunrn -1;
	return 0;
}
//模板定义,以关键字template开始
//后跟一个模板参数列表
//这是一个以逗号分隔的一个或多个模板参数的列表,用<>包围起来
//eg:template <typename T, typename U>
//注意,U前面的关键字是必须要有的
  • 实例化函数模板
  • 当我们调用一个函数模板时,编译器用函数的实参来推断模板实参
  • cout<< compare(1, 0)<<endl; //T为int
  • vector< int > vec1{1,2,3}, vec2{4,5,6};
  • cout<< compare(vec1, vec2)<<endl; //T为vector< int >

  • 类型模板参数
template <typename T>
T foo( T *p)
{
	T temp = *p;
	...
	return temp;
}
//意思就是,模板的类型参数的类型,也可以作为返回类型

  • 非类型模板参数
  • 表示一个值,而非类型
  • 我们通过一个其自身的类型名来定义该参数,而非上面我们使用的template/class
    在这里插入图片描述

  • inline和constexpr的函数模板
  • 函数模板可以声明为inline或constexpr的
  • 将说明符放在模板参数列表之后返回类型之前
template <typename T> inline T min(const T&, const t&); //正确

inline template <typename T>  T min(const T&, const t&); //错误,说明符位置不对

  • 模板的编译
  • 当编译器遇到一个模板定义时,它不生成代码,只有当我们实例化出模板的一个特定版本时,编译器才会生成代码
  • 模板特点: 模板的头文件通常既包括声明也包括定义!
  • 大多数错误,在实例化期间报告

类模板

  • 类模板是用来生成类的蓝图的
  • 与函数模板不同的是,编译器不能为类模板推断参数类型

定义类模板

  • 与函数模板类似,类模板以关键字template开始,后跟模板参数列表
  • plus P568-570
//原先的类:
typedef unsigned long Item;
class Stack
{
private:
	enum{MAX = 10};
	Item items[MAX];
	int top;
public:
	Stack(); //默认构造函数
	~Stock();
	bool isfull() const;
	bool push(Item &item);
}

//模板类
//就是将unsigned long 换为T
template <typename T>
class Stack
{
private:
	enum{MAX = 10};
	T items[MAX];
	int top;
public:
	Stack(); //默认构造函数
	~Stock();
	bool isfull() const;
	bool push(T &item);
}

//函数:
//此处特别强调,要在类的所有成员函数前面都加上:template <typename T>
//而不管这个函数内有没有用到模板的T
template <typename T>
Stack<T>::Stack()
{
	top=0;
}

template <typename T>
bool Stack<T>::isfull()
{
	return top == MAX;
}

等等...

  • 类模板与友元
  • 模板类也可以有友元,分为三类:
  • Plus P588
  • 1.非模板的友元函数
//在模板类中,将一个常规函数声明为友元:
//它会成为,模板所有实例化后的类,的友元

template <typename T>
class HasFriend
{
public:
	friend void counts();
	...
}

//也可以这样:
template <typename T>
class HasFriend
{
public:
	friend void counts(HasFriend <T> & );
	...
}
  • 2.约束模板友元
  • 就是在类外声明
  • 区别就是:每一个类的具体化,都对应着其各自的友元函数
//首先在类定义前面声明每个模板函数
template <typename T> void counts() ;

template <typename TT>
class HasFriendT   //c是一个普通的类
{
	...
	friend void counts <TT> (); 
	...
}
  • 3.非约束模板友元
  • 在类内声明
  • 其友元模板类型参数与模板类型参数是不同的
  • 区别就是:所有具体化的类,都对应着一个友元函数
template <typename T>
class ManyFriend   //c是一个普通的类
{
	...
	template <typename C, typename D>  friend void show (C &,  D 7); 
	...
}

  • 模板参数
  • 模板参数名的可用范围,是在其声明之后,至模板声明/定义结束之前
  • 模板参数会隐藏外层作用域中声明的相同名字
  • 但是,在模板内不能重用模板参数名
typedef double A;
template < typename A, typename B > void f(A a, B b)
{
	A tmp = a;  ///tmp的类型为模板参数A 的类型,而不是double
	double B; //错误:重声明模板参数B
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值