《C++ Template. The Complete Guide》笔记之一 缘起

从面对《Modern C++ Design》中backEnds.template的用法一无所知开始,要彻底搞清楚C++的模板是如果工作的决心其实已经埋下了。更何况今天在实现B树的时候反复被模板的编译问题折磨着。更加坚定了看完这本《C++ Template. The Complete Guide》的信念。尽管过去对这个主题知道一些东西,什么特化,偏特化,参数演绎等等。但是系统地看一看也是有必要的。当然在这里学习的时候还是非常同意Nocolai的观点,实用才是王道,因为我不是科学家也不可能成为科学家:)。

 

在这里学习的开始,还是乐意重复一遍那个经典的主题:Why Templates?

理由很简单,在设计数据结构或者算法的时候,需要对不同的数据类型,但是相似的行为做描述。比如说你有一个QuickSort,你想让他能对int,float, std::string都能够排序。

你有很多办法:第一就是你实现3个QuickSort, 参数分别是int[],float[],std::string[],这样是可以工作的。但是带来的问题显而易见,如果你第一次实现的int的排序是错的,那你完蛋了,你必须把这三个实现都改了。如果这个代码是你一个人维护那勉强可以,如果很多人维护,别人可不知道有这样的历史在代码里面。所以这个方案是不妥当的。

第二个方法,其实是比较常见的,就是void*或者Object来取代具体的类型,每次我实现一个容器的时候push_back的内容都是Object&或者void*,用这个Object&或者void*来代替了具体的类型。这样的好处是确实你不用重写三分代码了,但是问题一样很明显,用过了void*以后需要类型转化,原先的类型信息丢失了。在这样的情况下,一个float也被类型转化成了int加入到排序的队列中,而这确实不显示你的想法。如果Object&也一样有问题,如果待排序的数据ObjectA同时继承与ObjectB和ObjectC,而这两个父类又都是Object的子类,那样那个讨厌的菱形有出现了!!!简单的说这种对待排序参数强制的要求在维护性上是得不到很好的保证的。

当然,在模板没有应用的时候,还有人用了宏定义来取代模板。让我们来看看那些曾经熟悉的身影:

#define SWAP(a, b) { / a ^= b; / b ^= a; / a ^= b; / } #define MAX(a, b) ((a) < (b) ? (b) : (a))

如果不是那些C/C++的大师不断强化这个MAX或者MIN的写法,我想这种"stupid replacement mechanism"肯定会让很多人抓狂。是的,这样的宏定义太容易出错了,在C++里面,他不断的被取代,简单的函数变成了inline,值define编程了enum。总之C++的基调就是忘记宏,忘记预定义。

所以在这样的时刻,在这个C#和Java都在推动template的时刻。我们还有什么理由不用C++的模板呢?

 

 

你可能感兴趣的:(《C++ Template. The Complete Guide》笔记之一 缘起)