这几天用template的郁闷和自己的无知(1)

 想做一个自己的元胞自动机模板库,结果就把自己搞晕了:

1. Template Template Parameters

想在模板类中封装一个容器,容器的类型可以由用户指定,容器中元素的类型也可以由用户指定。

于是想当然而

template<typename CellType, typename ContainerType>

class CellContainer

{

     ......

     ContainerType<CellType> m_cellSet;

     ......

}

 

想当然而的东西当然不对,通不过编译,自己也知道,恐怕没有这么简单解决。找了google这个最好的老师,搜到C++ Common Knowledge: Essential Intermediate Programming 这本书,还有电子版。原来这个技术叫做Template Template Parameters,如获至宝。

 

捣鼓了半天,这么做了:

 

template<typename CellType, template <typename> class ContainerType>

class CellContainer

{

     ......

     ContainerType<CellType> m_cellSet;

     ......

}

 

 template <typename> class 表示后面的那个ContainerType也是一个模板类,而且是含有一个模板参数的模板类。

 

光是模板类的编译是通过了,不过对于模板来说,不到具现它的时候是说明不了问题的。

果然,CellContainer<int, vector>

通过不了编译。说是vector和模板不匹配。

 

再次想办法,这回总算捡起《C++ template》这本经典了,(我的pdf板很差,不大高兴看它)。

终于找到,原来,STL容器是有默认Allocator的,只是我们从来不用,一律default。但是在这里,必须要告诉编译器,有两个模板参数才行。

template<typename CellType, 

                template<typename Elem,typename Alloc = std::allocator<Elem>> class ContainerType>
class CellContainer
{
       ContainerType<CellType> m_cellSet;
};

 

template<typename Elem,typename Alloc = std::allocator<Elem>>  class

表示后面的ContainerType是一个含有两个模板参数的模板类,并且第二个模板参数默认为std::allocator<Elem>

这样才和STL的Container对上了。

 

唉,还是自己学艺不精啊!STL基本的没搞透彻。

 

2 Template Specialization

 

template给我们的力量在于:对不同的型别的一致性处理。

但是,在设计template function或者template class的时候,型别的行为并不一定就是我们所预期的那样。当有的型别符合我们设计的意愿,但是又不容易融合到我们的template中来的时候,我们可以特殊处理之,那就叫特化( Specialization)。

例如(Modern C++ Design)中的例子

有模板类:

 

template <class Window, class Controller>
class Widget
{
   ... generic implementation ...
};

 

针对特定的ModalDialog, MyController类,我可以做特殊的处理:

template <>
class Widget<ModalDialog, MyController>
{
   ... specialized implementation ...
};

 

这样,当模板参数为ModalDialog, MyController时,我们的Widget的行为是后面特化后的行为。

 

如果,我们紧紧希望对MyController做特化,而这样的特化适用于任意Window与MyController的结合,那么我们可以做偏特化:

 

Partial Template Specialization

 

template <class Window>
class Widget<Window, MyController>
{
   ... partially specialized implementation ...
};

 

 

偏特化还有重要的一个用途就是在处理类似指针行为的型别的时候:

 

看例子(C++ templates : The Complete Gui

template<typename T> 
class List {          // (1) 
  public: 
    
   void append(T const&); 
   inline size_t length() const; 
    
}; 
这是一个List的模板类,但有时我们希望一个List中能存放不同类型的元素。在过去,我们利用指针void *做到这一点,
因为void*指针可以指向任意类型的对象。
而我们也知道,我们处理List<int*>::append()List<void*>::append() 的方式其实是一样的。也就是针对指针
型的型别,我们可以采用统一的算法。于是,我们可以专门针对指针型的元素,做上述模板类的偏特化
template<typename T> 
class List<T*> { // (2) 
  private: 
    List<void*> impl; 
     
  public: 
     
    void append(T* p) { 
        impl.append(p); 
    } 
    size_t length() const { 
        return impl.length(); 
    } 
     
}; 
不过这样又带来一个问题,因为偏特化的过程中,一个成员就是List<void*> impl; 
为了能够实现List<void*> 本身,我们再针对List<void*>做一个特化
template<> 
class List<void*> {   // (3) 
     
    void append (void* p); 
    inline size_t length() const; 
     
}; 
真是麻烦啊,感觉特化就是模板搞不定的事情的修修补补,毕竟静态多态是算法一致,类型不一致,但是算法又是对型别有要求的,
所以搞起来还是比动态多态麻烦。但是template是麻烦模板设计者,幸福模板用户的。对于用户来说,能获得又灵活又高效的库
是一件幸福的事情。效率,弹性,简单三大目标不可能兼得,C++取的是效率和弹性,简单只能被放弃了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值