您的位置:首页 > 编程语言 > C语言/C++

c++函数模板

2016-07-21 12:16 281 查看
要写一个通用的函数,比如说各种类型数据的加法,如何实现呢?对,我们学过函数重载。

int Add(const int &_iLeft, const int &_iRight)
{
return (_iLeft + _iRight);
}
float Add(const float &_fLeft, const float &_fRight)
{
return (_fLeft + _fRight);
}


通过函数重载我们可以获得一个通用的函数接口,可操作不同类型的数据。但是函数重载并不完美,它存在很多问题:

1、只要有新类型出现,就要重新添加对应函数。

2、除类型外,所有函数的函数体都相同,代码的复用率不高。

3、如果函数只是返回值类型不同,函数重载不能解决。

我们可以定义一个函数模板,来进行对任意类型的数据操作

模板属于泛型编程,即编写与类型无关的逻辑代码,是代码复用的一种手段。模板是泛型编程的基础。



函数模板:代表了一个函数家族,该函数与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

写一个函数模板:

tempalate<typename T>
int Add(const T&left,const T&right)
{
return (left+right);
}


模板定义时以关键子template,后跟一个模板参数列表(template parameter list),这是一个逗号分隔的一个或多个模板参数的列表,用”<”和”>”包围起来。typename可用class代替。

在使用模板时,绑定实参后编译器自动识别数据类型。

cout<<Add(1,2)<<endl;   //T为int


模板是一个蓝图,它本身不是类或者函数,编译器用模板产生指定的类或者函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化。

实例化之前,检查模板代码本身,查看是否出现语法错误,如:遗漏分号

在实例化期间,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些函数调用。

非类型模板参数

除了定义类型参数,还可以在模板中定义非类型参数。一个非类型参数表示一个值而非一个类型。当一个模板被实例化时,非类型参数被一个用户提供的或编译起推断出来的值所替代。

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


当我们调用这个版本的compare时:

compare("hi","mom");


编译器自动计算两字符串的字节数来代替N和M,实例化模板;



int compare(const char (&P1)[3],const char (&P2)[4]);


【实参推演】

从函数实参确定模板形参类型和值的过程称为模板实参推断多个类型形参的实参必须完全匹配

【类型形参转换】

一般不会转换实参以匹配已有的实例化,相反会产生新的实例。

编译器只会执行两种转换:

1、const转换:接收const引用或者const指针的函数可以分别用非const对象的引用或者指针来调用

2、数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指针转换。数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针。

模板参数

函数模板有两种类型参数:模板参数和调用参数





模板形参说明

1、模板形参表使用<>括起来

2、和函数参数表一样,跟多个参数时必须用逗号隔开,类型可以相同也可以不相同

3、模板形参表不能为空

4、模板形参可以是类型形参,也可以是非类型新参,类型形参跟在class和typename后

5、模板类型形参可作为类型说明符用在模板中的任何地方,与内置类型或自定义类型

使用方法完全相同,可用于指定函数形参类型、返回值、局部变量和强制类型转换

6、模板形参表中,class和typename具有相同的含义,可以互换,使用typename更加直观。但关键字typename是作为C++标准加入到C++中的,旧的编译器可能不支持。

模板函数重载

int Max(const int& left, const int & right)
{
return left>right? left:right;
}
template<typename T>
T Max(const T& left, const T& right)
{
return left>right? left:right;
}
template<typename T>
T Max(const T& a, const T& b, const T& c)
{
return Max(Max(a, b), c);
};
int main()
{
Max(10, 20, 30);
Max<>(10, 20);
Max(10, 20);
Max(10, 20.12);
Max<int>(10.0, 20.0);
Max(10.0, 20.0);
return 0;
}


注意:函数的所有重载版本的声明都应该位于该函数被调用位置之前。

【说明】

1、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

2、对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调动非模板

函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。

3、显式指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,而且所有的模板参数都应该根据实参演绎出来。

4、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息