C++模板参数替换的理解
还是邓俊辉老师数据结构中List那一章的例子。
List的遍历问题。
main.cpp里调用PRINT ( La ); // La是一个自定义的List对象
PRINT这个宏的定义就在main.cpp里#define PRINT(x) { print(x); crc(x); checkOrder(x); }
print的声明在UniPrint/print.h里
template <typename T> static void print ( T& x ) { UniPrint::p ( x ); } #include "print_implementation.h"
注意C++模板类的定义和实现必须要在同一个文件中,通常是头文件,因为编译器要看到模板实现才能展开模板。
但是print.h里的模板类UniPrint只有方法的声明,没有方法的实现。
所以print.h的末尾引入了print_implementation.h这个头文件。UniPrint::p的实现就在这个头文件里。
这也是C++模板类的常用写法。
print_implementation.h里又引入了Print_traversable.h,UniPrint::p的真正实现在Print_traversable.h里。(windows上C++头文件不分大小写)
print_traversable.h
template <typename T> //元素类型 void UniPrint::p ( T& s ) { //引用 printf ( "%s[%d]*%d:\n", typeid ( s ).name(), &s, s.size() ); //基本信息 s.traverse ( print ); //通过print()遍历输出所有元素 printf ( "\n" ); }
运行到s.traverse( print );
这一句的时候会跳到traverse方法里去。
list.h
template <typename T> void List<T>::traverse ( void ( *visit ) ( T& ) )//借助函数指针机制遍历 { for (ListNodePosi(T) p = header->succ; p != trailer; p = p->succ) { printf("%s", "sss"); visit(p->data); } // 因为T已经被替换成了int。所以这里的visit其实是UnitPrint::p的模板实例,在print_basic.cpp里 }
从traverse方法来看,它接收的是一个函数指针,这个函数接收一个T型引用的参数,且没返回值。
所以s.traverse ( print );中print方法也应该接收一个T型引用的参数。
纵观print.h中只有这一句符合条件:template <typename T> static void print ( T& x ) { UniPrint::p ( x ); }
咦?不对呀,这怎么又回来了?怕不是死循环?
是的,这个地方卡了我好久。后来我想通了。PRINT里调用print的时候,会先走到print_traversable.h里去执行UniPrint::p的实现,
执行到s.traverse(print);这一句后,是在traverse这个方法里调用print的。这个时候UniPrint::p和traverse里的T已经被替换成int类型了。
也就是模板已经被实例化了。所以debug的时候发现,虽然程序又走到了
print.h中的这一句:template <typename T> static void print ( T& x ) { UniPrint::p ( x ); }
但不会再次走到print_traversable.h里,因为T已经被替换了。 此时程序会找 void print(int& x){UniPrint::p(x);}
的实现,
也就是这里:
print_basic.cppvoid UniPrint::p ( int e ) { printf ( " %04d", e ); }
C++中没有print函数。这个print是自己定义的哟。
搞清楚了这个, #define PRINT(x) { print(x); crc(x); checkOrder(x); }
里crc(x)就好理解了。几乎是同样的道理。
crc_list
template <typename T> void crc ( List<T> & L ) { //统计列表的特征(所有元素总和) T crc = 0; L.traverse ( Crc<T> ( crc ) ); //以crc为基本操作进行遍历 printf ( "CRC =" ); print ( crc ); printf ( "\n" ); //输出统计得到的特征 }
crc_Elem.h
template <typename T> struct Crc { //函数对象:累计T类对象的特征(比如总和),以便校验对象集合 T& c; Crc ( T& crc ) : c ( crc ) {} virtual void operator() ( T& e ) { c += e; } //假设T可直接相加 };
所谓函数对象就是定义了调用操作符()的类对象。当用该对象调用此操作符时,其表现形式如同普通函数调用一般,因此取名叫函数对象
与print不同的地方在于这里调用的是traverse的另一个版本:
List_traverse.h
template <typename T> template <typename VST> //元素类型、操作器 void List<T>::traverse ( VST& visit ) //借助函数对象机制遍历 { for (ListNodePosi(T) p = header->succ; p != trailer; p = p->succ) { visit(p->data); } }
看,visit加一个圆括号,就是在用Crc重载后的运算符()。
对了,这个int什么时候传进去的?
在调用PRINT宏之前,在main函数这里传进去的:testList<int> ( atoi ( argv[1] ) );
testList也是一个模板方法:
template <typename T> //元素类型 void testList ( int testSize ) { PRINT ( La ); // La是一个自定义的List对象
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值
原文: json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值 主要内容: 一、json相关概念 二、json字符串转换成json对象 (字符串-->JSON对象) 三、json对象转换成字符串(json对象-->字符串) 四、将值转换成字符串(值-->字符串) 五、字符串转成值(字符串-->值) 同步的交流学习社区:http://www.mwcxs.top/page/425.html 一、json相关概念 json,全称为javascript object notation,是一种轻量级的数据交互格式。采用完全独立于语言的文本格式,是一种理想的数据交换格式。 同时,json是javascript是原生格式,所以javascript操作处理json不需要任何包,api,任何依赖。 json中有两个结构:(1)数组(2)对象 (1)什么是数组 数组就是以"["开始,以“]”结束的,值之间运用 “,”(逗号)分隔。 比如: [{ "key": "test1", "value": 123, "type": "number", "re...
- 下一篇
学习jupyter notebook的安装与使用
欢迎关注大数据和人工智能技术文章发布的微信公众号:清研学堂,在这里你可以学到夜白(作者笔名)精心整理的笔记,让我们每天进步一点点,让优秀成为一种习惯! 一、jupyter notebook是什么 官网的介绍是:Jupyter Notebook是一个Web应用程序,允许您创建和共享包含实时代码,方程,可视化和说明文本的文档。 用途包括:数据清理和转换,数值模拟,统计建模,机器学习等等。 简单的介绍就是:Jupyter Notebook是Ipython的升级版,而Ipython可以说是一个加强版的交互式 Shell,也就是说,它比在terminal里运行python会更方便,界面更友好,功能也更强大。怎么强大法,往下看就知道了。 二、jupyter notebook的安装和打开 安装非常简单,只需要在终端输入: [plain] view plain copy pipinstalljupyter 打开jupyter notebook 也只需要在终端输入: [plain] view plain copy jupyternotebook 运行上面的命令之后,你将看到类似下面这样的输出: 如...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Mario游戏-低调大师作品
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7