• 第59课 类模板深度剖析


    多参数类模板:

    特化:

    上图特化的意义是将原来接收任意两个类型参数的模板特化为只能接收一种类型的两个参数。

    这意味着如果定义类时我们给的两个参数是同种类型的,则编译器优先使用右边的这种模板实现。

    一个类模板实际分开实现为两个部分,编译器根据具体的参数选择其中的一个模板。

    编译器会认为上图中的两个Test模板是同一个,具体实现时,如参数类型不同则选择左边的实现,参数类型相同时选择右边的实现。

     完全特化就是我们根本就不需要泛指参数了,直接指定原先的泛指类型全部为int,完全特化意味着特化之后的模板里面已经没有了泛指类型。

    当我们使用模板时,如果指定了参数都为int,则编译器选择右边的实现。

    示例程序:

    编译器并不认为第20行是一个新的模板,只是认为它是第7行那个模板的一个特殊实现。

     使用double*和int*来生成类:

    1 Test<int*, double*> t4;
    2     int a = 1;
    3     double b = 0.1;
    4     
    5     t4.add(&a, &b);

    这次匹配到了第7行的这个模板实现,但是第二次编译时,编译器提示我们两个不同的指针类型无法相加。

    因此,我们继续添加指针参数的特化。

    继续完善:

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 template
     7 < typename T1, typename T2 >
     8 class Test
     9 {
    10 public:
    11     void add(T1 a, T2 b)
    12     {
    13         cout << "void add(T1 a, T2 b)" << endl;
    14         cout << a + b << endl;
    15     }
    16 };
    17 
    18 template
    19 < typename T1, typename T2 >
    20 class Test < T1*, T2* >      // 关于指针的特化实现
    21 {
    22 public:
    23     void add(T1* a, T2* b)
    24     {
    25         cout << "void add(T1* a, T2* b)" << endl;
    26         cout << *a + *b << endl;
    27     }
    28 };
    29 
    30 template
    31 < typename T >
    32 class Test < T, T >    // 当 Test 类模板的两个类型参数完全相同时,使用这个实现
    33 {
    34 public:
    35     void add(T a, T b)
    36     {
    37         cout << "void add(T a, T b)" << endl;
    38         cout << a + b << endl;
    39     }
    40     void print()
    41     {
    42         cout << "class Test < T, T >" << endl;
    43     }
    44 };
    45 
    46 template
    47 <  >
    48 class Test < void*, void* >    // 当 T1 == void* 并且 T2 == void* 时
    49 {
    50 public:
    51     void add(void* a, void* b)
    52     {
    53         cout << "void add(void* a, void* b)" << endl;
    54         cout << "Error to add void* param..." << endl;
    55     }
    56 };
    57 
    58 int main()
    59 {  
    60     Test<int, float> t1;
    61     Test<long, long> t2;
    62     Test<void*, void*> t3;
    63     
    64     t1.add(1, 2.5);
    65     
    66     t2.add(5, 5);
    67     t2.print();
    68     
    69     t3.add(NULL, NULL);
    70     
    71     Test<int*, double*> t4;
    72     int a = 1;
    73     double b = 0.1;
    74     
    75     t4.add(&a, &b);
    76     
    77     return 0;
    78 }

    以上的四个类模板是一个模板,只不过有几种不同的特化方式。

    结果如下:

     多参数类模板:

    问题:

    特化的深度分析:

     示例:

    我们将void* 指针参数的特化注释掉,重新定义Test_Void类,第75行也改成Test_Void类名字,这样也能正常工作。

    但是,在我们编程时要时刻想着到底是使用类模板呢还是Test_Void类呢?这无疑增加了负担,所以能用类模板特化的就用特化,不能特化的再重新定义类。

    函数模板示例:

    上图中我们得到了正确的结果,但是我们知道两个浮点数比较不能直接用45行的比较方法,因此,我们需要特化。

    改进如下:

    从打印结果看,double类型确实调用到了第52行的特化版本。

    再添加一个直接重载的版本:

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 template
     7 < typename T1, typename T2 >
     8 class Test
     9 {
    10 public:
    11     void add(T1 a, T2 b)
    12     {
    13         cout << "void add(T1 a, T2 b)" << endl;
    14         cout << a + b << endl;
    15     }
    16 };
    17 
    18 /*
    19 template
    20 <  >
    21 class Test < void*, void* >    // 当 T1 == void* 并且 T2 == void* 时
    22 {
    23 public:
    24     void add(void* a, void* b)
    25     {
    26         cout << "void add(void* a, void* b)" << endl;
    27         cout << "Error to add void* param..." << endl;
    28     }
    29 };
    30 */
    31 
    32 class Test_Void
    33 {
    34 public:
    35     void add(void* a, void* b)
    36     {
    37         cout << "void add(void* a, void* b)" << endl;
    38         cout << "Error to add void* param..." << endl;
    39     }
    40 };
    41 
    42 template
    43 < typename T >
    44 bool Equal(T a, T b)
    45 {
    46     cout << "bool Equal(T a, T b)" << endl;
    47     
    48     return a == b;
    49 }
    50 
    51 template
    52 < >
    53 bool Equal<double>(double a, double b)
    54 {
    55     const double delta = 0.00000000000001;
    56     double r = a - b;
    57     
    58     cout << "bool Equal<double>(double a, double b)" << endl;
    59     
    60     return (-delta < r) && (r < delta);
    61 }
    62 
    63 bool Equal(double a, double b)
    64 {
    65     const double delta = 0.00000000000001;
    66     double r = a - b;
    67     
    68     cout << "bool Equal(double a, double b)" << endl;
    69     
    70     return (-delta < r) && (r < delta);
    71 }
    72 
    73 int main()
    74 {  
    75     cout << Equal( 1, 1 ) << endl;
    76     cout << Equal<>( 0.001, 0.001 ) << endl;
    77     
    78     return 0;
    79 }

     运行结果如下:

    当第76行为cout << Equal(0.001, 0.001) << endl 时,结果如下:

    调用的是我们的重载的函数版本。

    当第76行为cout << Equal<>(0.001, 0.001) << endl 时,调用的是函数模板特化版本,如下:

    工程中的建议:

     小结:

  • 相关阅读:
    ProtoBuf开发者指南(转)
    kafka的c/c++高性能客户端librdkafka简介
    SQL的执行顺序:
    zookeeper与卡夫卡集群搭建
    记一次ping: unknown host错误
    nginx服务器的rewrite功能
    nginx做http向https的自动跳转
    jQuery数据缓存
    jQuery的无new构建
    位操作符的计算优势
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9589245.html
Copyright © 2020-2023  润新知