C++之模板与泛型编程

定义模板

函数模板

template <typename T>
int compare (const T &v1, const T &v2){
	if (v1 < v2) return -1;
	if (v2 < v1) return 1;
	return 0;
}

当我们调用一个函数模板时,编译器用函数实参来为我们推断模板实参

cout<<compare(1,0)<<endl;

除了定义类型参数,还可以在模板中定义非类型参数一个非类型参数表示一个值而非一个类型。我们通过一个特定的类型名而非关键字class或typename来指定非类型参数

</font color=“red”>当一个模板被实例化时,非类型参数被一个用户提供的或编译器推断出的值所代替。这些值必须是常量表达式,从而允许编译器在编译时实例化模板。
例如:

template<unsigned N,unsigned M>
int compare(const char (&p1)[N],const char (&p2)[M]){
	return strcmp(p1,p2);
}

编译器会使用字面常量的大小来代替N和M,从而实例化模板。
在模板定义内,模板非类型参数是一个常量值。在需要常量表达式的地方,可以使用非类型参数,例如,指定数组大小。

编写泛型代码的两个重要原则:

  • 模板中的函数参数是const的引用
  • 函数体中的条件判断仅使用<比较运算

通过将函数参数设定为const的引用,我们保证了函数可以用于不能拷贝的类型。大多数类型,包括内置类型和我们已经用过的标准库类型(除unique_ ptr 和I0类型之外),都是允许拷贝的。但是,不允许拷贝的类类型也是存在的。通过将参数设定为const 的引用,保证了这些类型可以用我们的compare函数来处理。而且,如果compare用于处理大对象,这种设计策略还能使函数运行得更快。

当编译器遇到一个模板定义时,它并不生成代码。只有当我们实例化出模板的一个特定版本时,编译器才会生成代码。当我们使用(而不是定义)模板时,编译器才生成代码, .这一特性影响了我们如何组织代码以及错误何时被检测到。

通常,当我们调用一个函数时,编译器只需要掌握函数的声明。类似的,当我们使用一个类类型的对象时,类定义必须是可用的,但成员函数的定义不必已经出现。因此,我们将类定义和函数声明放在头文件中,而普通函数和类的成员函数的定义放在源文件中。

模板则不同:为了生成一个实例化版本,编译器需要掌握函数模板或类模板成员函数的定义。因此,与非模板代码不同,模板的头文件通常既包括声明也包括定义。

类模板

类模板与函数模板的不同之处是:**编译器不能为类模板推断模板参数类型。**为了啥用类模板,我们必须在模板名后的尖括号提供额外信息。

类模板与友元

//前置声明,在Blob中声明友元所需要的
template <typename> 
class BlobPtr;
template <typename> 
class Blob; // 运算符==中的参数所需要的
template <typename T>
bool operator==(const Blob<T>&const B1ob<T>&) ;
template <typename T> 
class Blob {
	//每个Blob实例将访问权限授予用相同类型实例化的BlobPtr和相等运算符
	friend class B1obPtr<T>;
	friend bool operator==<T>(const Blob<T>&const Blob<T>&);
};

类模板与static

类模板的每个实例都有一个独有的static对象。因此,与定义模板的成员函数类似,我们将static数据成员也定义为模板:

template<typename T>
size_t Foo<T>::ctr = 0; //定义并初始化ctr

模板实例化

函数实例化

//compare的特殊版本,处理字符数组的指针
template<>
int compare(const char* const& p1,const char* const& p2){
	return strcmp(p1,p2);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值