大多数c和c++程序员会这样的组织他们的非模板代码:
类和其他类型放在头文件中,对于全局变量和(非内联)函数,只有声明放在头文件中,定义则位于.cpp文件中,这样我们的代买就可以工作了,然而在模板代码中,这一切在有的编译器中并不可行。原因就是:在我们编译过程中,大多数编译器会通过,但是链接器却会出问题:因需要用到的模板函数的定义还没有被实例化。为了实例化,编译器必须知道,应该实例化模板的哪个定义以及要基于哪个模板实参进行实例化。遗憾的是,我们的非模板代码组织方式,把这两部分信息放到了分开编译的两个文件中。因此,当编译器看到我们的函数调用的时候,只是假设函数定义出现在了别处,并产生一个指向该定义的引用(让链接器利用该引用解决问题)。然而,当我们在编译器还有函数定义的.cpp文件的时候,我们并没有针对特定实参编译(实例化)我们的模板定义的代码,这样出现了错误。我们可以采用包含模型、显式实例化、分离模型加以解决。
一、包含模型有三种实现方式:
1、.cpp文件include到.h的末尾;
2、在所有用到该模板函数的地方,include .cpp文件,这也是比较常用的一个方式;
3、把.h和.cpp整合成一个.h文件
二、显式实例化:
我们可以仍像原来那样组织我们的代码:
.h中放声明,.cpp中放置定义,然后在main函数所在的.cpp中调用模板函数,然而这时我们需要提供另一个.cpp文件,该文件需要include放置模板函数定义的.cpp(有时候为了体现该.cpp是希望用来被include的,我们也将其扩张名改为.h),然后在该.cpp中,我们需要显式声明,只是注意:已经显式实例化的成员函数,不能再次实例化。
显式实例化的格式:template 返回值类型 函数名<数据类型>(具体函数类型 形参);
例如:template void func<double>(double const&);
三、分离模型
需要用到关键字export,尽管现在能支持export的编译器很少,但是将来有可能会受到重视。
export的使用是很简单的:再一个文件里定义模板,并在模板的定义和(非定义的)声明前面加上关键字export就可以了(必须写在template前面)。
我们只需要在第一个声明前面加上关键字就可以了(必须写在template前面),在以后的重复声明或者定义中会隐式的保留这个export声明。
注意:我们的export必须写在template前面。
export和inline不能同时使用,故在文件中,显式内联和隐式内联(类中定义函数)都不能被导出(export)。
当然,我们在实际使用中,可以利用预处理符号决定使用哪种模型,具体见C++ Templates。