C++学习笔记35:函数模板
函数模板
函数模板的目的
- 设计通用的函数,以适应广泛的数据型式
函数模板的定义格式
- template<模板型式参数列表>返回值型式 函数名称(参数列表);
- 原型:template<class T> void Swap(T &a, T&b);
- 实现:template<class T> void Swap(T &a , T&b){...}
函数模板的体化与特化
- 针对特定型参数,在声明或第一次调用该函数模板时体化
- 每次体化都形成针对特定型参数的重载函数版本
- 文件最终只保留特定型参数的一份体化后的函数
- 显式体化主要用于库的设计;显式特化覆盖体化的同型函体
//函数模板
template<class T> void f(T t) {/* */}
//显式体化:使用显式的长整型模板参数
template void f<long>(long n);
//显式体化:使用d的型式推导模板参数型式
template void f(double d);
//显式特化:使用显式的整型参数
template<> void f<int> (int n);
//显式特化:使用c的型式推导模板参数型式
template<> void f(char c);
template <class T> void Swap(T &a, T &b)
{
T a; t = a, a = b, b = t;
}
int main()
{
int m = , n = ;
char a = 'A', b = 'B';
double c = 1.0, d = 2.0;
//正确调用,体化Swap(int &,int &)
Swap(m, n);
//正确调用,体化Swap(char &,char &)
Swap<char>(m, n);
//正确调用,体化Swap(double &, double &)
Swap<double>(c, d);
return ;
}
函子
编写函数,求某个数据集的最小元,元素型式为T
- 实现策略:使用函数指针作为回调函数参数
- 实现策略:使用函子(function object, functor)作为回调函数参数
函数指针实现
//const T *a 指向数据集的基地址
//n为元素的个数
template<typename T>
const T &Min(const T *a, int n, bool(*compare)(const T&, const T&))
{
int index = ;
for (int i = ; i < n; i++)
{
if (comparer(a[i], a[index]))
index = i;
}
return a[index];
}
函子
函子的目的
功能上:类似函数指针
实现上:重载函数调用操作符,必要时重载小于比较操作符
函子的优点
函数指针不能内联,而函子可以,效率更高
函子可以拥有任意数量的额外数据,可以保证结果和状态,提高代码的灵活性
编译时可对函子进行型式检查
函子实现
//使用方法
int a[8] = {9,2,3,4,5,6,7,8};
int min = Min(a,8,Comparer<int>());//构造匿名函子作为函数参数
template<typename T>class Comparer
{
public:
//确保型式T已存在或重载operator<
bool operator()(const T &a, const T &b)
{
return a < b;
}
}; template<typename T,typename Comparer>
const T &Min(const T *a, int n, Comparer comparer)
{
int index = ;
for (int i = ; i < n; i++)
{
if (comparer(a[i], a[index]))
index = i;
}
return a[index];
}
完美转发
完美转发的意义
- 库的设计者需要设计一个通用的函数,将接受到的参数转发给其他函数
- 转发过程中,所有参数保持原先的语义不变
完美转发的实现策略
- 当需要同时提供移动语义和拷贝语义时,要求重载大量建构函数,编程量大,易出错
- 右值引用与函数模板相互配合,可以实现完美转发,极大降低代码编写量
例子:
class A
{
public:
A(const string &s, const string &t) :_s(s), _t(t) {}
A(const string &s, string && t) :_s(s), _t(move(t)) {}
A(string &&s, const string &t) :_s(move(s)), _t(t) {}
A(string &&s, string &&t) :_s(move(s)), _t(move(t)) {}
private:
string _s, _t;
};
int main()
{
string s1("Hello");
const string s2("World");
A a1(s1, s2);
A a3(string("Good"), s2);
A a2(s1, string("Bingo"));
A a4(string("Good"), string("Bingo"));
return ;
}
改进后:
class A
{
public:
//根据实际参数型式生成不同的左值或右值引用的建构函数版本
//T1或T2可以不同型,此处相同仅为示例
//实参推演时,使用引用折叠机制
//当形式参数为T&&型时,当且仅当实际参数为右值或者右值引用时
//实际参数型式才为右值引用
//引用折叠机制与const/volatile无关,保持其参数性质不变
//std::forward<T>(t)转发参数的右值引用T&&
template<typename T1, typename T2> A(T1 &&s, T2 &&t)
:_s(std::forward<T1>(s)), _t(std::forward<T2>(t)) {}
private:
std::string _s, _t;
};
C++学习笔记35:函数模板的更多相关文章
- Matlab学习笔记 figure函数
Matlab学习笔记 figure函数 matlab中的 figure 命令,能够创建一个用来显示图形输出的一个窗口对象.每一个这样的窗口都有一些属性,例如窗口的尺寸.位置,等等.下面一一介绍它们. ...
- matlab学习笔记 bsxfun函数
matlab学习笔记 bsxfun函数 最近总是遇到 bsxfun这个函数,前几次因为无关紧要只是大概看了一下函数体去对比结果,今天再一次遇见了这个函数,想想还是有必要掌握的,遂查了些资料总结如下. ...
- 微信小程序开发:学习笔记[2]——WXML模板
微信小程序开发:学习笔记[2]——WXML模板 快速开始 介绍 WXML 全称是 WeiXin Markup Language,是小程序框架设计的一套标签语言,结合小程序的基础组件.事件系统,可以构建 ...
- matlab学习笔记13_1 函数返回值
一起来学matlab-matlab学习笔记13函数 13_1 函数返回值 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 https://blog.csdn.net/qq_36556 ...
- C++学习笔记2_函数.函数指针.函数模板
1. 内联函数void printAB(int a,int b){ cout<<(a)<<(b)<<endl;}int main(void){ for(int i= ...
- c++学习笔记之函数重载和模板理解
1.函数重载: C++ 不允许变量重名,但是允许多个函数取相同的名字,只要参数表不同即可,这叫作函数的重载(其英文是 overload).重载就是装载多种东西的意思,即同一个事物能完成不同功能. 所谓 ...
- swift学习笔记2——函数、闭包
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- haskell学习笔记_函数
一开始学习函数式编程语言就被告知函数式编程语言是一种“定义式”的语言,而不是一种命令式的语言,在学习haskell的函数语法时,此感觉更加强烈,haskell的函数定义倾向于一种类似C++里面的swi ...
- Python学习笔记之函数
这篇文章介绍有关 Python 函数中一些常被大家忽略的知识点,帮助大家更全面的掌握 Python 中函数的使用技巧 1.函数文档 给函数添加注释,可以在 def 语句后面添加独立字符串,这样的注释被 ...
随机推荐
- 时间序列数据库选型——本质是列存储,B-tree索引,抑或是搜索引擎中的倒排索引
时间序列数据库最多,使用也最广泛.一般人们谈论时间序列数据库的时候指代的就是这一类存储.按照底层技术不同可以划分为三类. 直接基于文件的简单存储:RRD Tool,Graphite Whisper.这 ...
- 436. Find Right Interval ——本质:查找题目,因此二分!
Given a set of intervals, for each of the interval i, check if there exists an interval j whose star ...
- Java 生成压缩包,ZipOutputStream的使用
案例:根据url 获取网络资源A,B,C 将资源A,B,C放在一起生成一个xxx.zip 直接看代码 import java.io.File; import java.io.FileOutputS ...
- linux 查看僵尸进程
top -b -i -n 1 查看僵死进程命令 ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' 查看apache 当前进程数 ps -ef | grep ht ...
- 使用MediaPlayer和SurfaceView播放视频
使用VideoView播放视频简单.方便,丹有些早期的开发者更喜欢使用MediaPlayer来播放视频,但由于MediaPlayer主要用于播放音频,因此它没有提供图像输出界面,此时 需要借助于Sur ...
- PHP 长字符串替换操作性能(替换多换注释的代码)
因为写一个css合并工具,去掉注释时,发现正则表达式很难写,最后,还是用php来实现吧,但是一不小心写出来的代码居然报内存超出可用的128m!! 原因是因为我找到/*和*/之后 $str=substr ...
- ASP.NET MVC学习之控制器篇(二)
原文链接:http://www.asp.net/learn/mvc/ 这篇教程探索了ASP.NET MVC控制器(controller).控制器动作(controller action)和动作结果(a ...
- 关于HashMap中的负载因子
这两天在看HashMap的时候,被负载因子float loadFactor搞得很晕,经过一天的研究,最后理出了自己的一点个人见解. 在HashMap的底层存在着一个名字为table的Entry数组,在 ...
- 通过获取DNS解析的未转义主机名,区分测试环境和正式环境代码
ASP.Net编程中经常有一些代码,测试环境下需要执行,而正式环境下不需要执行(或者反之). 我们经常做的方式是:去掉注释,测试,再注释,再编译上传(或者反之). 现在,不妨试试以下办法: Reque ...
- STM32之延时秒,毫秒,微秒
#include "delay.h" #include "stdint.h" #include "stm32f10x.h" ; //us延时 ...