• Step By Step(C++模板重载和特化)


    一、模板函数重载:

        函数重载是一个非常通用亦非常容易理解的编程基础概念,既函数名相同而函数签名不同的一组函数,在实际的调用中,编译器会根据函数参数的不同自动选择最为合适且最为特化的函数。在推演的过程中,如果出现多个函数均符合该调用规则,编译器将根据其内置的特化规则,选择最为特殊的函数作为候选函数。然而如果仍有多个候选函数的话,编译器将报出二义性错误。和普通函数一样,在C++中模板函数也同样支持函数重载的功能,甚至可以将模板函数与普通函数混合在一起,以达到更为灵活的函数重载的效果。
        在这里,我们对于函数重载的概念本身将不再做过多的赘述了,而是将重点放在模板函数重载的应用场景和应用技巧上。下面我将给出一个利用模板函数重载计算哈希值的代码示例:

     1     #include <stdio.h>
     2     
     3     template<typename T> 
     4     int hash_code(T v) {
     5         return v.hashCode() * 2;
     6     }
     7     
     8     template<typename T>
     9     int hash_code(T* v) {
    10         return v->hashCode();
    11     }
    12     
    13     int hash_code(const int v) {
    14         return v + 100;
    15     }
    16     
    17     class HashClass {
    18     public:
    19         HashClass(int v) : _v(v) {}
    20         int hashCode() {
    21             return _v + 200;
    22         }
    23     
    24     private:
    25         int _v;
    26     };
    27     
    28     int main() {
    29         HashClass c1(10);  //调用的是template<typename T> int hash_code(T v)
    30         printf("The hash value is %d\n",hash_code(c1));
    31         HashClass c2(20);  //调用的是template<typename T> int hash_code(T* v)
    32         printf("The hash value is %d\n",hash_code(&c2));
    33         int i3 = 30;      //调用的是int hash_code(const int v)
    34         printf("The hash value is %d\n",hash_code(i3));
    35         return 0;
    36     }
    37     
    38     //The hash value is 420
    39     //The hash value is 220
    40     //The hash value is 130

        在上面的示例代码中,hash_code函数可以让编译器根据参数的不同选择最为合适的候选函数。在这里模板函数和普通函数一同参与了函数重载。对于模板函数重载,主要应用于算法领域,既对于大多数的类型可以通过泛型算法以达到预期的效果,而对于特殊类型,则可以通过函数重载的方式,针对该类型实现另外一套更为高效的算法。
        
    二、模板类特化:

        对于模板类而言,也同样存在和模板函数重载类似的应用场景,但是在模板类中则是以模板类特化的方式存在。在下面的示例代码为生产者-消费者的任务缓冲队列,当清空队列中的已有元素时,亦需考虑如何释放元素对象本身可能占用的系统资源。这里会根据不同的元素类型,给出不同的元素释放类。

     1     #include <stdio.h>
     2     #include <vector>
     3     
     4     using namespace std;
     5     
     6     class Runnable {  
     7     public:
     8         virtual void release() {
     9             delete this;
    10         }
    11     };
    12     
    13     class Closable {
    14     public:
    15         virtual void close() {
    16             _db.close();
    17             delete this;
    18         }
    19     private:
    20         db_env _db;
    21     };
    22     
    23     template<typename T>
    24     class List {   //1
    25     public:
    26         void clear() { 
    27             _taskList.clear();
    28         }
    29     private:
    30         vector<T> _taskList;
    31     };
    32     
    33     template<typename T>
    34     class List<T*> {  //2
    35     public:
    36         void clear() {
    37             for (int i = 0; i < _taskList.size(); ++i)
    38                 delete _taskList[i];
    39             _taskList.clear();
    40         }
    41     private:
    42         vector<T*> _taskList;
    43     };
    44     
    45     template<>
    46     class List<char*> {  //3
    47     public:
    48         void clear() {
    49             for (int i = 0; i < _taskList.size(); ++i)
    50                 delete [] _taskList[i];
    51             _taskList.clear();
    52         }
    53     private:
    54         vector<char*> _taskList;
    55     };
    56     
    57     template<>
    58     class List<Runnable*> {  //4
    59     public:
    60         void clear() {
    61             for (int i = 0; i < _taskList.size(); ++i)
    62                 _taskList[i]->release();
    63             _taskList.clear();
    64         }
    65     private:
    66         vector<Runnable*> _taskList;
    67     };
    68     
    69     template<>
    70     class List<Closable*> {  //5
    71     public:
    72         void clear() {
    73             for (int i = 0; i < _taskList.size(); ++i)
    74                 _taskList[i]->close();
    75             _taskList.clear();
    76         }
    77     private:
    78         vector<Runnable*> _taskList;
    79     };
    80     
    81     int main() {
    82         List<Runnable*> listRunnable;  //调用No 4
    83         List<Closable*> listClosable;  //调用No 5
    84         List<int> listInt;             //调用No 1
    85         List<int*> listIntPointer      //调用No 2
    86         List<char*> listCharPointer;   //调用No 3
    87         return 0;
    88     }

        在上面的代码示例中,编译器会根据模板参数的不同而选择不同的模板类,然而这一切对于调用者而言又是完全透明的,如果今后再增加新的特殊类型时,仅需为该类型实现一个新的特化类即可。需要说明的,该代码片段完全是为了演示这个C++模板特征而编写的,仅供参考。

  • 相关阅读:
    shell 命令
    unzip解压失败 添加tar 解压
    tomcat
    Linux常用命令
    压缩归档与解压
    Linux的任务计划管理
    A01. openstack架构实战-openstack基本环境准备
    ubuntu16.04 server版破解密码
    Ubuntu Server 18.04 网络设置不生效的解决
    带宽单位 Mbps 及换算方式
  • 原文地址:https://www.cnblogs.com/orangeform/p/2625195.html
Copyright © 2020-2023  润新知