Jul 31, 2008

变相实现C++类模板的分离式编译

  今天在拜读过pongba的一篇关于C++编译机制的文章后(http://blog.csdn.net/pongba/archive/2003/10/24/19130.aspx),找到一种变相实现类模板分离式编译的方法。
  这里所谓的分离式编译,是指把类的定义和成员函数的实现分别置于独立的.h和.cpp文件中。对于一般的类,这样做是没有问题的,而如果试图将模板类的定义与实现分离,则大多数编译器会给出链接错误。这是因为单独定义的模板类成员函数无法被实例化(详细的分析请参见开头链接的那篇文章)。
  而解决这一问题的思路非常直接——手动让它们实例化。具体说来,就是在实现模板类成员函数的.cpp文件中再定义一个实例化函数,在这一函数中实例化类模板,并把所有的成员函数调用一遍。
  示例代码如下:

-----------------------
template.h
-----------------------
//定义类模板
template <class T>
class CTemplate
{
 T m;

public:
 void fun(void);
};


-----------------------
template.cpp
-----------------------
#include "template.h"

//实现类模板的成员函数
template <class T>
void CTemplate<T>::fun(void)
{
 m++;  //假设类型T有合法的++运算符
}

//实现分离式编译的关键——专门用来实例化模板类成员函数的函数
void instantiate(void)
{
 CTemplate<int> instance;
 instance.fun();  //在这里调用一次CTemplate::fun(),就可避免出现链接错误
}


-----------------------
main.cpp
-----------------------
#include "template.h"

int main()
{
 //主函数这里ct的fun()调用可以顺利进行,
 //但是要注意用来实例化模板类的数据类型应与instantiate()中使用的相一致,
 //这里使用的都是int型。
 //若想使用其他数据类型,比如float,
 //则需要在instantiate()中用同样的方法对float做实例化。
 CTemplate<int> ct;
 ct.fun();

 return 0;
}

  另外要说明的是,这种方法并不会增加运行时的时间开销,因为instantiate()并没有在main()的调用堆栈中出现,它的作用仅仅是让编译器为模板类的成员函数生成二进制代码,以消除链接错误。

No comments: