函数模板

函数模板概念

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

函数模板格式

//要让这个函数与类型无关
//Add函数模板
template<class T,typename s>  //模板的参数列表
//告诉编译器T是一种类型
T Add(T left, T right)
{return left + right;
}

函数模板原理

针对于下面的代码,我们看编译器给我们的反汇编代码,来了解函数模板编译器是怎么处理的?

T Add(T left, T right)
{cout << typeid(T).name() << endl;return left + right;
}
int main()
{//对函数模板实例化Add(1, 2);Add(1.0, 2.0);Add('1', '2');return 0;
}


每个函数地址不一样,说明编译器为每个类型都准备了相对应的函数
在编译阶段,如果编译器检测到对某个函数模板实例化

  1. 对实参类型进行推演(和函数重载有点像),根据推演的结果,确认模板参数列表中T的实际类型
  2. 将它集合函数模板,处理具体类型的函数,生成对应类型的函数

但是下面这个调用,就会报错,因为第一参数给成整型,编译器就会认为T是整型,但是第二个参数是double类型,那么编译器又认为T是double类型,两者冲突,编译器就不知道T到底是什么。
模板一般不会进行相应类型转化

Add(1,2.0)

解决方法:

T Add(T left, T2 right)
{cout << typeid(T).name() << endl;return left + right;
}

也可以手动进行强制类型转换
也可以这样调用Add<int>('1', '2.0');

函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显示实例化

隐式实例化

让编译器根据实参推演模板参数的实际类型

T Add(T left, T right)
{cout << typeid(T).name() << endl;return left + right;
}
int main()
{//对函数模板实例化Add(1, 2);Add(1.0, 2.0);Add('1', '2');return 0;
}
显示实例化

在函数名后的<>中指定模板参数的实际类型
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

Add<int>('1', '2.0');

函数模板参数的匹配原则

  1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
int Add(int left, int right)
{return right + left;
}
template<class T>
T Add(T left, T right)
{return left + right;
}int main()
{//同名函数与函数模板同时存在时,优先使用模板生成的函数Add<>(1, 2); //隐式实例化Add(1,2);return 0;
}
  1. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
int Add(int left, int right)
{return right + left;
}
template<class T>
T Add(T left, T right)
{return left + right;
}
int main()Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数return 0;
}
  1. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

类模板

类模板的定义

typedef int DataType;
template<class T>
class SeqList
{public:SeqList(size_t capacity = 10):_array(new T(capacity)), _size(0), _capacity(capacity){}~SeqList(){delete[] _array;_array = nullptr;_capacity = 0;_size = 0;}//尾部void PushBack(const T& data);void PopBack(){--_size;}//任意位置插入和删除/*void Insert(size_t pos, T&data);void Erase(size_t pos);*///在const类型成员函数中不能修改成员变量//const修饰this指针size_t size()const{return _size;}size_t Capacity()const{return _capacity;}bool Empty()const{return 0 == _size;}T&operator[](size_t index){assert(index < _size);return _array[index];}const T&operator[](size_t index) const{assert(index < _size);return _array[index];}
private:void _CheckCapacity(){if (_size == _capacity){//开辟新空间T* array = new T[2 * _capacity];//拷贝元素//memcpy(array, this->_array, _size*sizeof(T));for (size_t i = 0; i < _size; ++i){array[i] = _array[i];}//释放旧空间delete[] _array;_array = array;_capacity *= 2;}}
private:T* _array;size_t _size;size_t _capacity;
};
template<class T>
void  SeqList<T>::PushBack(const T& data)
{_CheckCapacity();_array[_size] = data;_size++;
}

类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

void TestSeqList()
{SeqList<int> s1;s1.PushBack(1);s1.PushBack(2);s1.PushBack(3);s1.PushBack(4);cout << s1[2] << endl;s1[2] = 10;cout << s1.size() << endl;cout << s1.Capacity() << endl;cout << s1[2] << endl;SeqList<double> s2;
}

初识c++中的函数模板相关推荐

  1. 深入理解c++中的函数模板

    非类型模板参数 模板参数分类类型形参与非类型形参. 类型形参:出现在模板参数列表中,跟在class或者typename之类的参数类型名称. 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类 ...

  2. c 语言 模板函数参数,深入解析C++中的函数模板和函数的默认参数

    C++函数模板 我们知道,数据或数值可以通过函数参数传递,在函数定义时它们是未知的,只有在发生函数调用时才能确定其值.这就是数据的参数化. 其实,数据类型也可以通过参数来传递,在函数定义是可以不指明具 ...

  3. C++ 函数模板和排序的函数模板——学习笔记

    我们在使用重载函数时,只是使用了函数名,而函数体还是得分别定义,在C++中函数模板为我们很好的解决了这个问题. 1.函数模板的声明 函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函 ...

  4. [c++][语言语法]函数模板和模板函数 及参数类型的运行时判断

    参考:http://blog.csdn.net/beyondhaven/article/details/4204345 参考:http://blog.csdn.net/joeblackzqq/arti ...

  5. C++11 函数模板的默认模板参数

    1.函数模板默认模板参数简介 函数模板与类模板在 C++98 一起被引入,因种种原因,类模板可以拥有默认模板参数,而函数模板不可以.从 C++11 开始,这个限制被解除了,即函数模板同样可以拥有默认模 ...

  6. VS2017 函数模板和类模板的声明、定义和使用

    模板的声明.定义分为两种. 1 将模板的声明和定义都放在头文件中,在主程序的文件中包含此头文件即可 2 将模板的声明和定义分开编写. 在<C++ primer>教材中,将模板的声明和定义分 ...

  7. 函数模板、 内联函数

       函数重载就是有相同的函数名但参数的个数或类型不同从而根据不同的参数个数和参数类型来调用相应的方法.    我们发现函数重载只是解决了函数命名的问题,但函数体虽然相同我们还是要重复的写,为了解决这 ...

  8. C++函数模板学习总结

    函数模板是什么? 通用函数描述,使用泛型来定义函数,其中的泛型可以用具体的类型来替换,使用函数模板的编程有时候也叫做泛型编程. 知识总结 在标准的C++98添加关键字typename之前,C++使用关 ...

  9. C++设计模式由浅入深(二)—— 类模板和函数模板

    二.类和函数模板 C++的模板编程特性是一个又大又复杂的话题,有许多著作专门传授这种特性和技巧.在本书中,我们会用到许多C++中的高级泛型编程特性.那么我们该如何去理解贯穿次数中的这些语言结构呢?本章 ...

最新文章

  1. 重磅!全球首个可视化联邦学习产品与联邦pipeline生产服务上线
  2. php 保存 json,保存PHP中的Array,是用JSON, serialize还是var_export?
  3. Web3.0来了!玩法变了
  4. 【深度学习的数学】2×3×1层带sigmoid激活函数的神经网络感知机对三角形平面的分类训练预测(绘制出模型结果三维图展示效果)(梯度下降法+最小二乘法+激活函数sigmoid+误差反向传播法)
  5. 条款11 在operator=中处理“自我赋值”
  6. activity 、window与view的关系 (上)
  7. java试卷_Java测试题及答案(Java干货完整试卷)
  8. (十一)OpenCV实现图像频率域滤波
  9. spring事务传播特性_关于spring的事务的传播propagation特性
  10. 图片在手机上怎么修改格式?怎么改变图片格式?
  11. 基于PSO算法的无线传感器网络的覆盖优化
  12. 如何想领导说清楚DCMM到底有什么好处?
  13. 解决用电脑连接宽带给手机开热点的问题
  14. 微信二维码无法下载APK解决方案,用Mindjump实现自动跳转浏览器
  15. 童玲:蚂蚁金服区块链在真实业务场景的实践与突破
  16. Python在计算机里快速查找文件
  17. 360极速浏览器用ie8模式打开网页(360浏览器同理)
  18. Day_06 传智健康项目-移动端开发-体检预约
  19. SeleniumWebDriver运行数据库测试?
  20. golang并发编程-04-通道-02-定时器、断续器

热门文章

  1. oracle 执行多条insert 语句
  2. 【C++】满二叉树问题
  3. 微信小程序常见问题集合(长期更新)
  4. Mycat 安装配置
  5. URAL 1106 Two Teams (DFS)
  6. hdu 1564 Play a game
  7. qt 试用 (3)配置编译源代码及调试
  8. java it_关于 Java Iterator(迭代器)学习笔记
  9. mysql怎么制作柱状图_从数据库中取出最近三十天的数据并生成柱状图
  10. java 英文字符串排序_英文字符串排序算法