C++模板参数替换的理解

简介: 还是邓俊辉老师数据结构中List那一章的例子。List的遍历问题。 main.cpp里调用PRINT ( La ); // La是一个自定义的List对象 PRINT这个宏的定义就在main.cpp里#define PRINT(x) { print(x); crc(x); checkOrder(x); } print的声明在UniPrint/print.

还是邓俊辉老师数据结构中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.cpp
void 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对象
目录
相关文章
|
2天前
|
存储 算法 编译器
C++的模板与泛型编程探秘
C++的模板与泛型编程探秘
11 0
|
2天前
|
编译器 C++
【C++从练气到飞升】08---模板
【C++从练气到飞升】08---模板
|
2天前
|
算法 编译器 C++
【C++入门到精通】新的类功能 | 可变参数模板 C++11 [ C++入门 ]
【C++入门到精通】新的类功能 | 可变参数模板 C++11 [ C++入门 ]
23 1
|
2天前
|
编译器 C语言 C++
【C++】模板进阶
【C++】模板进阶
14 1
|
2天前
|
存储 编译器 C++
【C++】内存管理和模板基础(new、delete、类及函数模板)
【C++】内存管理和模板基础(new、delete、类及函数模板)
24 1
|
2天前
|
C++
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
|
2天前
|
存储 算法 C++
详解C++中的STL(标准模板库)容器
【4月更文挑战第30天】C++ STL容器包括序列容器(如`vector`、`list`、`deque`、`forward_list`、`array`和`string`)、关联容器(如`set`、`multiset`、`map`和`multimap`)和容器适配器(如`stack`、`queue`和`priority_queue`)。它们为动态数组、链表、栈、队列、集合和映射等数据结构提供了高效实现。选择合适的容器类型可优化性能,满足不同编程需求。
|
2天前
|
运维 Serverless Go
Serverless 应用引擎产品使用之在阿里云函数计算中c++模板,将编译好的C++程序放进去部署如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
15 1
|
2天前
|
存储 C++
【C++模板】模板实现通用的数组
【C++模板】模板实现通用的数组
|
2天前
|
编译器 程序员 C++
C++从入门到精通:3.1模板编程——提高代码的复用性和灵活性
C++从入门到精通:3.1模板编程——提高代码的复用性和灵活性