模板特化

前言:

C++提供了一种特例机制,对于某个已有模板,可以为某个或者某组模板参数类型另外指定一种变体,以应付原模板无法处理的问题,或者提供更高效的实现方案.这种机制就称为模板特例.

 

模板特例一个典型的例子就是C++标准库中的容器类模板vector<T>。与数组相似,vector是一种将数据连续存放的容器.但与数组不同的是,vector容量可随所存数据增加而自动增加.vecotr<bool>则是vector<T>的一个特例,专门为存储布尔型值设计.布尔型只有两个值,真或者假,只需要1比特即可表示.1字节完全可以用来存储8个布尔型变量.如果采用基于sizeof(T)的算法,则1个布尔值占用1字节,显得太浪费.

我们将vector<bool>设计成用一系列整数值来保存压缩后的布尔值.

具体见代码:

#include <cstdio>
#include <iostream>
#include <stdexcept>

template<typename T>
class my_vector{
private:
     T * array;
     unsigned size;
     unsigned block_size;
public:
    my_vector(unsigned bsz):array((T*)malloc(sizeof(T)*block_size),size(0),
                              block_size(size){
                              }
    ~my_vector(){
         if(array){
               free(array);
         }
    }
    
    void push_back(const T& v) throw (std::runtime_error){
           if(size==block_size){
                  block_size*=2;
                  T *new_array=realloc(array,block_size*sizeof(T));
                  if(new_array!=NULL){
                        array=new_array;
                  }
                  
                  else{
                         free(array);
                         array=NULL;
                         throw std::runtime_error("Out of memory.");
                  }
           }
           array[size++]=elem;
    }
    
    T& operator[] (unsigned i) {return array[i];}
    const T& operator[] (unsigned i) const{return array[i];}
    
    //告诉我们占了多少内存
    unsigned get_mem_size() const{return block_size*sizeof(T);}
};


template<>
class my_vector<bool>{
private:
       int *array;
       unsigned size;
       unsigned block_size;
       //一个段(segment)即一个整数值,段大小为一个整数值所能容纳的最多布尔值
       const static unsigned seg_size;
public:
       my_vector(unsigned bsz):array((int*)malloc(sizeof(int)*bsz),size(0),
                                                       block_size(bsz){
                                                       }
       
       ~my_vector(){
              if(array){
                    free(array);
              }
       }
       
       void push_back(bool elem) throw (std::runtime_error){
               if(size==block_size){
                     block_size*=2;
                     int *new_array=(int*)realloc(array,sizeof(int)*block_size);
                     if(new_array){
                           array=new_array;
                     }
                     
                     else{
                          free(array);
                          array=NULL;
                          throw std::runtime_error("Out of memory.");
                     }       
               }
               
              set(size++,elem);
      }
      
      void set(unsigned i,bool elem){
             if(elem){
                   array[i/seq_size] |=(0x1 << (i%seq_size));
             }
             
             else{
                   array[i/seq_size] &=~(0x1 << (i%seq_size));
             }
      }
      
      bool operator[] (unsigned i) const{
             return array[i/seq_size] & (0x1 << (i%seq_size))!=0;
      }
      
      unsigned get_mem_size() const{
            return block_size* sizeof(int);
      }
};

const unsigned my_vector<bool>::seq_size =sizeof(int)*8;
    

 面试题:

 在软件公司的招聘考试中,经常出现的C/C++题目是:不使用循环及条件判断语句,打印1-100的数字.

 思路如下:

 这个问题可以通过采用编译器的递归调用来轻松解决问题.

  •  首先,既然不能采用循环的方式来打印,就只能采用"分而治之"的策略.那么"打印1~100的数"可以分解为"打印1~99的数"及"打印100的数"两个问题.依次类推,  则该问题显然可以通过递归来实现。
  • 模板特例实际上也是实现了一种条件判断逻辑-当模板参数满足某一匹配条件时所匹配的特例实现,否则用通例来实现.并且由于模板通例及特例是分别写在多个模板实现代码中,并不需要增加任何判断语句。

注意:

   不过模板特例所实现的判断逻辑是在编译器来执行,而不是在程序运行时基于输入值来判断,这就要求判断式的值在编译器已知.

解题思路还是按照递归方式,只是将递归函数改写成函数模板,将打印范围由函数参数变为模板参数.

代码:

#include <iostream>

template<int i>
void print(){
     print<i-1>();
     std::cout<<i<<std::endl;
}

//递归,终止递归
template<>
void print<1>(){
    std::cout<<1<<std::endl;
}

int main(){
    print<100>();
}

 

posted @ 2014-09-30 20:43  晓风_7  阅读(521)  评论(0编辑  收藏  举报