C++模板详解

来源:互联网 发布:舍恩伯格大数据时代 编辑:程序博客网 时间:2024/06/03 17:21

在平时写代码时,我们总会遇到这种问题:实现一个很简单的功能,但是由于传参过程中不同于形参类型的实参类型会使得你不得写多个功能相似的函数分别去实现他们,这就会造成许多问题,比如代码冗余,函数名太多造成名字空间的污染。这就需要其他方法来解决这种问题。之前在C语言学习中,我们学到了宏这一概念,宏可以一定程度上解决这个问题。但是宏也有它的缺点:
宏替换
宏是在预编译时展开的;
宏只是简单地文本替换;
宏不具有类型检测,语句是否正确等编译功能;
宏在定义时易出现宏参数二义性问题
所以在C++中就引入了模板这一概念,下面先来看看什么叫泛型编译,它与模板有什么联系?
泛型编程
面向对象编程(OOP)与泛型编程都能处理在编写程序时不知道类型的情况。不同之处是OOP能处理类型在程序运行之前都未知的情况;而泛型编程在编译时就能获知类型了。其中容器,迭代器,算法都是泛型编程的例子。当我们在编写一个泛型程序时,是独立于任何特定类型来编写代码的。当使用一个泛型编程时,我们提供类型或值,程序实例可在其上运行。

模板
模板就是泛型编程的基础。模板分为模板函数和模板类。

函数模板
一个函数模板就是一个公式,可用来生成针对特定类型的函数版本。模板函数定义以关键字template开始,后面跟模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用一对尖括号括起来。模板形参的定义既可以使用class,也可以使用typename,含义是一样的。

template<typename 形参名1,class 形参名2...>

函数模板的实例化
当我们调用一个函数模板时,编译器通常会根据函数实参来推演模板实参。即,编译器根据函数实参的类型来确定绑定到模板参数T的类型。

cout<<compare(1,0)<<endl;  //T为int

编译器推断出模板实参为int,并将它绑定到函数实参T。
编译器会根据推断出的模板参数来为我们实例化一个特定类型的函数。当编译器实例化一个模板时,它使用实际的模板实参来代替对应的模板参数来创建出模板的一个新实例。例如

int compare(const T &v1,const T &v2){}1cout<<compare(1,2)<<endl;   //T为int实例化出:int cout<<compare(const int& ,const int&){}2vector<int> vec1{1,2,3},vec2{4,3};cout<<compare(vec1,vec2)<<endl;  //T为vector<int>实例化出:int compare(const vector<int>&,const vector<int>&)

这里写图片描述

这里写图片描述
隐式实例化
模板并非函数定义,但使用的模板实例是函数定义的。这就是隐式实例化。

显示实例化
显示实例化意味着可以直接命令编译器创建特定的实例,格式是“template <实例化的类型> 函数名(参数列表)”

cout<<IsEqual<int>(1,1.2)<<endl;cout<<IsEqual<int ,double>(1.2,1.2) <<endl;

模板类型参数
一般说来,我们将类型参数看作类型说明符,就像内置类型或类类型说明符使用。特别是,类型参数可以用来指定返回值类型或函数的参数类型,以及在函数体内用于变量声明或类型转换。
非类型模板参数
除了定义参数类型,我们还可以在模板中定义非类型参数。非类型参数就是指他表示一个值而不是一个参数。
我们通过一个特定的类型名而非关键字class或typename来指定非参数类型。当有一个模板被实例化时,非类型参数被编译器推演出的值代替,这些值必须为常量表达式,从而允许编译器在编译时实例化模板。
一个非类型参数可以是一个整形或是一个指向对象或函数类型的指针或引用。绑定到非类型整形参数的实参必须是一个常量表达式。绑定到指针或引用的非类型参数的实参必须具有静态的生存期。

2 0
原创粉丝点击