C++函数模板学习总结

函数模板是什么?

通用函数描述,使用泛型来定义函数,其中的泛型可以用具体的类型来替换,使用函数模板的编程有时候也叫做泛型编程。

知识总结

在标准的C++98添加关键字typename之前,C++使用关键字class来创建函数模板。

// 函数声明,声明时也要用模板的方式
template <typename T>
void Swap(T &a, T &b);

注意函数模板不能缩短可执行程序,最终的代码不包含任何模板,而只包含了为程序生成的实际函数。使用函数模板的好处是,使得生成多个函数定义更加的简单、可靠。

并非所有的模板参数都必须是模板参数类型。

模板函数也可以用来重载。

要注意函数模板的局限性,如对结构进行比较大小等操作时,模板函数可能无法处理某些类型。

具体化

可以提供一个具体化的定义,称为显示具体化。

.对于给定的函数名,可以有:
非模板函数
模板函数
显示具体化模板函数
以及他们的重载类型。

显示具体化的原型和定义应该以:
template<>
开头,并通过名称来指出类型。

优先级关系:
非模板函数 > 显示具体化函数
显示具体化函数 > 常规模板函数

template <typename T>
void Swap(T &, T &);

// 显示具体化函数的声明
template <> void Swap<job> (job &, job &);
// 等价于
template <> void Swap<> (job &, job &);

在代码中包含函数模板本身并不会生成函数定义,它只是一个用于函数定义的方案。

最初,编译器只能通过隐式实例化,来使用模板生产函数定义,但现在C++还允许使用显示实例化(explicit instantiation)。

// 显示实例化的声明
template void Swap<int> (int, int);
// 显示具体化的声明
template<> void Swap<int> (int &, int &);
template<> void Swap<> (int &, int &); // 等价

注意:视图在同一个文件(或转换单元)中使用同一种类型的显示实例和显示具体化将出错。

可以通过在程序中使用函数来创建显示实例化。

template<class T>
T Add(T a, T b)
{
	return a + b;
}

int m = 6;
double x = 6.66666;
double ans  = Add<double> (x, m);

隐式实例化、显示实例化和显示具体化统称为具体化(specialization) 。

重载解析

  1. 创建候选函数列表。
  2. 使用候选函数列表创建可行函数列表
  3. 确定是否有最佳的可行函数

在第一步中,锁定同名的函数和函数模板。

在第二步中,创建的都是参数数目正确的函数,有一个隐式转换序列,包括实参类型与形参类型完全匹配的情况。

第三步就是匹配,匹配成功,就可以使用他,匹配不成功,调用报错。

最佳匹配顺序
  1. 完全匹配,但是正常的函数要优于模板函数。
  2. 提升转换
  3. 标准转换
  4. 用户自定义的转化
错误情况

正常请胯下,如果有多个匹配的原型,则编译器无法完成重载解析过程。

如果没有最佳的可行函数,编译器会出现二义性的报错。

ambiguous——二义性

例外

但有些情况下,即使有两个函数完全匹配,却仍旧可以正常的执行。

例如,

  1. 执行非const数据的指针和引用,优先于const指针和引用。
  2. 非模板函数的完全匹配由于模板函数(包括显示具体化)的完全匹配。
  3. 如果两个完全匹配都是模板函数,则较具体的模板函数优先。即显示具体化优于隐式具体化。
    最具体并不一定意味着显示具体化,而是值编译器推断使用哪种类型的时候,执行的转换最少。
#include <iostream>

using namespace std;

template<class T>
T adds(T a, T b, T c)
{
	return a + b + c;
}

template <typename T>
T pows(T a, T b, T c) 
{
	// 乘法int不会自动转化成longlong
	return  a * b * c;
}

template <class T1, typename T2>
auto try_not_same(T1 a, T2 b) -> decltype(a + b)
{
	return a + b;
}

int main()
{
	cout << adds(5, 6, 9) << endl;
	cout << pows(500, 2000, 100000) << endl;
	cout << try_not_same(4, 4.0) << endl;
	
	return 0;
}

总结:当你感觉概念模糊不清的时候,试着写两个例子,你会发现,其实并非你想想的那样困难,这样的设计,有其巧妙之处,你可以学习到很多的知识,最重要的是,你会写了,你下次遇到的时候,不会很害怕了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值