一个猥琐的方法:解决模板类静态成员重定义的问题

C++类静态成员必须显示定义,而模板类要写在一个.h文件里,于是出现下面这总情况:
// some_template.h

template 
< class  T >
class  some_class
{
    public:
    
static T *ptr;
        T* get_ptr(){return ptr;}
}
;

template 
< class  T >
T
*  some_class < T > ::ptr  =  NULL;

// 1.cpp

#include 
" some_template.h "



some_class
< int >  foo;


// 2.cpp

#include 
" some_template.h "



some_class
< int >  bar;


将以上三个文件编译,就会出现some_class<int>::ptr的重定义。

帖子发了以后忽然想到一个解决办法,能部分的解决这个问题,顺便也解决了模板类在.h文件中定义在.cpp文件中实现的问题。但是这个方法:1. 比较繁复;2. 有时不见得能用;3. 确实比较猥琐...

其实问题的中心在于C++编译器把一个.cpp文件编译成一个.obj文件,当你在一个.cpp文件中使用了某个.h文件中声明的内容时,编译器并没有把相应的实现内容取过来,而是留下一个外部引用的记号,再由连接器把引用和实现连接起来。但我们使用模板时,比如说在上面的1.cpp中,我们使用了some_class<int>这个类,当我们编译1.cpp的时候,如果some_class<T>这个模板的实现不在 some_template.h中,编译器就会留下一个记号,等着连接器来连接。然后编译器就去编译别的文件了。而当编译器编译到some_class<T>的实现(比如说在some_template.cpp文件中)时,编译器不知道你再1.cpp文件中使用了some_class<int>,于是它没有生成相应的二进制代码。当然连接器就找不到some_class<int>,进而报错了。

some_class<int>的实现代码没有被生成,那我们就让他生成。唯一的办法是让编译器编译到some_template.cpp时知道some_class<int>被使用了,这很简单,我们使用一次就好了。

具体的办法如下:
在.h文件中只保留some_class的类定义:
// some_template.h

template 
< class  T >
class  some_class
{
public:
    
static T *ptr;
    T
* get_ptr();
}
;

在.cpp文件中实现some_class:
// some_template.cpp

template 
< class  T >
T
*  some_class < T > ::ptr  =  NULL;

template 
< class  T >
T
*  some_class < T > ::get_ptr()
{
    
return ptr;
}


#include 
" gen_some_class.h "

在上边的最后一行有一个#include  " gen_some_class.h ",我们在这个gen_some_class.h中写入生成模板类实例的代码:
// gen_some_class.h

void  gen_some_class()
{
    some_class
<int> sci;
    sci.get_ptr();
}

这里的void gen_some_class()是一个谁都不会调用的函数,但是他会让编译器意识到some_class<int>被使用了,some_class<int>::get_ptr()也被使用了,这样编译器就会生成相关代码,连接器就可以将相关代码链接到任何使用它的地方。

事情就这样解决了。

对于比较复杂的情况,比如有100个方法的类,被特化了100个版本,在void gen_some_class()中把100个对象的100个方法逐个调用一边,显然是抽风的做法...另外,对于不能实例化的类(包含纯虚方法),还要费更多的周折。所以基本上这个方法是没有什么应用性的,权当消遣。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值