万星星@豌豆荚 欢迎加入我们
一个吃软饭的男人!!!!!我只想写程序####
微博:http://weibo.com/wanlianwen
posts - 172,  comments - 1253,  trackbacks - 0

模板是一种源码复用技术,在某些情况下使用它可以使代码看起来非常优雅,著名的boost库就是模板发扬的典范.
然而模板也存在弊端,大量使用模板可能导致代码膨胀.下面介绍一种解决的方案:

我们首先看一段一般代码:

template < typename T >
class  Vector
{
public :
    
virtual   void  Say()
    
{
        
const  type_info &     t  =  typeid(T);
        std::cout 
<<   " Vector< "   <<  t.name()  <<   " >::Hello "   <<  std::endl;
    }

}
;

//  特例化
template <>
class   Vector < void *>
{
public :
    
virtual   void  Say()
    
{
        std::cout 
<<   " Vector<void*>::Hello "   <<  std::endl;
    }

}
;

int  _tmain( int  argc, _TCHAR *  argv[])
{
    Vector
< int *>     pIntVec;
    pIntVec.Say();
    Vector
< double *>     pDoubleVec;
    pDoubleVec.Say();
    
return   0 ;
}


输出:
Vector<int *>::Hello
Vector<double *>::Hello
从这里,我们可以看出程序在运行的过程中生产了两分Vector的代码(int*和double*),尽管这里有特例化,然而类型不匹配,编译器在编译过程中无法定位到特例化版本.如果这个Vector被滥用的化,我想即使是一个中等规模的程序也可能耗费成兆字节的代码控件.

我们必须寻找一种中间桥梁使编译器在编译过程中定位到void*的特例化版本.按照模板选择策略,编译器总是选择最特例化的模板,我们可以通过一个中间的模板联系起上面两个版本的模板.下面看一段代码:

template < typename T >
class  Vector
{
public :
    
virtual   void  Say()
    
{
        std::cout 
<<   " Vector::Hello "   <<  std::endl;
    }

}
;

//  特例化
template <>
class   Vector < void *>
{
public :
    
virtual   void  Say()
    
{
        std::cout 
<<   " Vector<void*>::Hello "   <<  std::endl;
    }

}
;

//  特例化
template < typename T >
class  Vector < T *>  :  public  Vector < void *>
{
}
;

int  _tmain( int  argc, _TCHAR *  argv[])
{
    Vector
< int *>     pIntVec;
    pIntVec.Say();
    Vector
< double *>     pDoubleVec;
    pDoubleVec.Say();
    
return   0 ;
}


输出:
Vector<void*>::Hello
Vector<void*>::Hello
从这里,我们可以看出程序在运行过程中全部使用Vector<void*>的版本.class Vector<T*>模板便是关键的环节.编译器在编译过程中,由于class Vector<T*>比class Vector更特例化,所以遇到Vector<int*>和Vector<double*>时都选择class Vector<T*>,而class Vector<T*>继承Vector<void*>,一个更加特例化版本,所以编译器不再产生新的模板而采用Vector<void*>这个最特例化版本,这样所有指针模板都归结到Vector<void*>,而class Vector<T*>为用户提供了一个精美而且安全的界面,而Vector<void*>作为底层实现细节被隐藏.

以上代码在VC 7.1(VS2003)中编译通过,由于VC6对模板支持不好,所以模板的高级用法一般不要在VC6中使用.
下载演示代码

posted on 2006-03-27 18:54 万连文 阅读(2313) 评论(7)  编辑 收藏 引用 所属分类: 模板

FeedBack:
# re: 抑制模板代码膨胀的一种技术
2006-03-27 20:08 | vender
不要这么别扭吧,直接偏特化好了
template<typename T>
class Vector<T*>
{
public:
virtual void Say()
{
std::cout << "Vector<void*>::Hello" << std::endl;
}
};
  回复  更多评论
  
# re: 抑制模板代码膨胀的一种技术
2006-03-27 20:15 | vender
而且你提到的这个“技巧”还是无法避免代码膨胀

由于此例过于简单,打开优化的编译器有可能仅仅产生一份代码,但原则上(例如不打开优化等)Vector<int*>和Vector<double*>还是会产生两份代码  回复  更多评论
  
# re: 抑制模板代码膨胀的一种技术
2006-03-28 11:25 | 万连文
你指的麻烦我主要是为了演示效果,看编译器到底调用哪个版本,
你指的过于简单也没有道理,举一反三,两个难道不能代表问题吗??如果不能我可以写3个,并且我没有打开任何优化器,结果显示确实是一份代码。顺便提一下,这个技术是看C++ program language(C++之父)里面提到的,感觉很好玩,所以动手测试了一下,发现真可以运做。  回复  更多评论
  
# re: 抑制模板代码膨胀的一种技术
2006-03-28 11:41 | 小明
我觉得vendor兄说的有道理阿,直接对T*进行偏特话就ok了。多一个void *的版本有什么意义呢?  回复  更多评论
  
# re: 抑制模板代码膨胀的一种技术
2006-03-28 11:48 | 万连文
如果没有void *版本,你可以把
public:
virtual void Say()
{
std::cout << "Vector::Hello" << std::endl;
}
放到
// 特例化
template<typename T>
class Vector<T*> : public Vector<void*>
{
};
看下结果是不是产生两份代码  回复  更多评论
  
# re: 抑制模板代码膨胀的一种技术
2006-03-28 11:50 | 万连文
最终目的就是让所有指针模板使用<void *>那一份代码,这样减少代码膨胀  回复  更多评论
  
# re: 抑制模板代码膨胀的一种技术
2006-03-29 15:05 | 万连文
不好意思,今天再次体会了一下,上面示例和解释存在问题:
在特例化的例子里面确实生成了2个版本的类<double*>和<int*>,这种技术减少代码主要表现在函数体公用上面,比如一个20行的函数pushback,实例化20次(20个指针版本)就是400行代码,如果公用<void*>版本,假设每个调用<void*>版本是4行,加上<void*>版本的20行将是20*4+20=100行,确实减少不少代码。
不知道这次理解是否正确。  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


简历下载
联系我

<2006年3月>
2627281234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(66)

随笔分类

随笔档案

相册

搜索

  •  

最新评论

阅读排行榜

评论排行榜