59-类模板深度剖析

注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。

测试环境:Ubuntu 10.10

GCC版本:9.2.0

 

一、多参数类模板

1)类模板可以定义任意多个不同的类型参数

函数模板也可以支持多个不同类型参数。 

使用类模板必须一一指定类型。

 

2)类模板可以被特化

        -    指定类模板的特定实现

        -    部分类型参数必须显示指定

        -    根据类型参数分开实现类模板

特殊化为只接受一个类型(T1和T2类型相同)。在指定实际类型时,如果T1和T2类型相同,编译器会优先使用右边的模板。编译器会根据实际情况分析使用左边或者右边。编译器认为这两个模板是同一个,在使用的时候会根据参数进行选择使用。

 

3)类模板的特化类型

        -    部分特化 - 用特定规则约束类型参数

        -    完全特化 - 完全显示指定类型参数

完全特化里没有泛指类型。 如果编译器指明T1、T2使用int,编译器会使用完全特化。

 

编程实验
类模板的特化
59-1.cpp
#include <iostream>
#include <string>

using namespace std;

template
< typename T1, typename T2 >
class Test    //多参数类模板
{
public:
    void add(T1 a, T2 b)
    {
        cout << "void add(T1 a, T2 b)" << endl;
        cout << a + b << endl;
    }
};

int main()
{  
    Test<int, float> t1;
    
    t1.add(1, 2.5);    //3.5
    
    return 0;
}

操作:

1) 使用模板:g++ 59-1.cpp -o 59-1.out编译正确,打印结果:

void add(T1 a, T2 b)
3.5

分析:

        使用模板时必须显示声明模板参数类型。

2) 使用模板特化:

#include <iostream>
#include <string>

using namespace std;

template
< typename T1, typename T2 >
class Test    //多参数类模板
{
public:
    void add(T1 a, T2 b)
    {
        cout << "void add(T1 a, T2 b)" << endl;
        cout << a + b << endl;
    }
};
//模板特化(部分特化:加了约束调价T1和T2相同)
template
< typename T >
class Test < T, T >    //当Test类模板的两个类型参数完全相同时,使用这个实现
{
public:
    void add(T a, T b)
    {
        cout << "void add(T a, T b)" << endl;
        cout << a + b << endl;
    }
};

int main()
{  
    Test<int, float> t1;
    Test<long, long> t2;
    
    t1.add(1, 2.5);    //3.5
    t2.add(5, 5);
    
    return 0;
}

g++ 59-1.cpp -o 59-1.out编译正确,打印结果:

void add(T1 a, T2 b)
3.5    
void add(T a, T b)    
10    

小实验:

#include <iostream>
#include <string>

using namespace std;

template
< typename T1, typename T2 >
class Test    //多参数类模板
{
public:
    void add(T1 a, T2 b)
    {
        cout << "void add(T1 a, T2 b)" << endl;
        cout << a + b << endl;
    }
};
//模板特化(部分特化:加了约束调价T1和T2相同)
template
< typename T >
class Test < T, T >    //当Test类模板的两个类型参数完全相同时,使用这个实现
{
public:
    void add(T a, T b)
    {
        cout << "void add(T a, T b)" << endl;
        cout << a + b << endl;
    }
    
    void print()
    {
        cout << "class Test < T, T >" << endl;
    }
};

int main()
{  
    Test<int, float> t1;
    Test<long, long> t2;
    
    t1.add(1, 2.5);    //3.5
    t2.add(5, 5);
    t2.print();
    
    return 0;
}

g++ 59-1.cpp -o 59-1.out编译正确,打印结果:

void add(T1 a, T2 b)
3.5    
void add(T a, T b)    
10    
class Test < T, T >    

3) 使用完全特化:

#include <iostream>
#include <string>

using namespace std;

template
< typename T1, typename T2 >
class Test    //多参数类模板
{
public:
    void add(T1 a, T2 b)
    {
        cout << "void add(T1 a, T2 b)" << endl;
        cout << a + b << endl;
    }
};
//模板特化(部分特化:加了约束调价T1和T2相同)
template
< typename T >
class Test < T, T >    //当Test类模板的两个类型参数完全相同时,使用这个实现
{
public:
    void add(T a, T b)
    {
        cout << "void add(T a, T b)" << endl;
        cout << a + b << endl;
    }
    
    void print()
    {
        cout << "class Test < T, T >" << endl;
    }
};
//完全特化
template     //当 T1 == void* 并且 T2 == void*时
< >
class Test < void*, void* >
{
public:
    void add(void* a, void* b)
    {
        cout << "void add(void* a, void *b)" << endl;
        cout << "Error to add void* param..." << endl;
    }
};    
    
int main()
{  
    Test<int, float> t1;
    Test<long, long> t2;
    Test<void*, void*> t3;
    
    t1.add(1, 2.5);    //3.5
    t2.add(5, 5);
    t2.print();
    
    t3.add(NULL, NULL);
    
    Test<int*, double*> t4;
    int a = 1;
    double b = 0.1;
    
    t4.add(&a, &b);
    
    return 0;
}

g++ 59-1.cpp -o 59-1.out编译错误:

59-1.cpp: In instantiation of ‘void Test<T1, T2>::add(T1, T2) [with T1 = int*; T2 = double*]’:
在实例'void Test<T1, T2>::add(T1, T2) [T1 = int*; T2 = double*]':
59-1.cpp:76:15:   required from here
59-1.cpp:14:13: error: invalid operands of types ‘int*’ and ‘double*’ to binary ‘operator+’
   cout << a + b << endl;
错误:类型'int*'和'double*'相加是非法操作

解决办法:定义一个类模板,用于指针类型相加

#include <iostream>
#include <string>

using namespace std;

template
< typename T1, typename T2 >
class Test    //多参数类模板
{
public:
    void add(T1 a, T2 b)
    {
        cout << "void add(T1 a, T2 b)" << endl;
        cout << a + b << endl;
    }
};

template 
< typename T1, typename T2 >
class Test < T1*, T2* >    //关于指针的特化实现
{
public:
    void add(T1* a, T2* b)   
    {
        cout << "void add(T1 a, T2 b)" << endl;
        cout << *a + *b << endl;
    }
};
    
//模板特化(部分特化:加了约束调价T1和T2相同)
template
< typename T >
class Test < T, T >    //当Test类模板的两个类型参数完全相同时,使用这个实现
{
public:
    void add(T a, T b)
    {
        cout << "void add(T a, T b)" << endl;
        cout << a + b << endl;
    }
    
    void print()
    {
        cout << "class Test < T, T >" << endl;
    }
};
//完全特化
template     //当 T1 == void* 并且 T2 == void*时
< >
class Test < void*, void* >
{
public:
    void add(void* a, void* b)
    {
        cout << "void add(void* a, void *b)" << endl;
        cout << "Error to add void* param..." << endl;
    }
};    
    
int main()
{  
    Test<int, float> t1;
    Test<long, long> t2;
    Test<void*, void*> t3;
    
    t1.add(1, 2.5);    //3.5
    t2.add(5, 5);
    t2.print();
    
    t3.add(NULL, NULL);
    
    Test<int*, double*> t4;
    int a = 1;
    double b = 0.1;
    
    t4.add(&a, &b);
    
    return 0;
}

g++ 59-1.cpp -o 59-1.out编译正确,打印结果:

void add(T1 a, T2 b)
3.5
void add(T a, T b)
10
class Test <T, T>
void add(void* a, void* b)
Error to add void* param...
void add(T1* a, T2* b)
1.1 

4)类模板特化注意事项

        -    特化只是模板的分开实现

            * 本质上是同一个类模板

        -    特化类模板的使用方式是统一的

            * 必须显示指定每一个类型参数

 

二、问题

        类模板特化与重定义有区别吗?

            函数模板可以特化吗?

            

三、特化的深度分析

1)重定义和特化的不同

    -    重定义

        * 一个类模板和一个新类(或者两个类模板)

        * 使用的时候需要考虑如何选择的问题

    -    特化

        * 以统一的方式使用类模板和特化类(只有一个类模板)

        * 编译器自动优先选择特化类

 

2)函数模板只支持类型参数完全特化

template
< typename T >    //函数模板定义
bool Equal(T a, T b)
{
    return a == b;
}

template
< >            //函数模板完全特化
bool Equal<void*>(void* a, void* b)
{
    return a == b;
}

测试:模板的重定义

#include <iostream>
#include <string>

using namespace std;

template
<typename T1, typename T2>
class Test
{
public:
    void add(T1 a, T2 b)
    {
        cout << "void add(T1 a, T2 b)" << endl;
        cout << a + b << endl;
    }
};
 
template
<typename T1, typename T2>
class Test <T1*, T2*>
{
public:
    void add(T1* a, T2* b)
    {
        cout << "void add(T1* a, T2* b)" << endl;
        cout << *a + *b << endl;
    }
};

template
<typename T>
class Test<T, T>
{
public:
    void add(T a, T b)
    {
        cout << "void add(T a, T b)" << endl;
        cout << a + b << endl;
    }
    
    void print()
    {
        cout << "class Test <T, T>" << endl;
    }
};
/*
template 
< >
class Test<void*, void*>
{
public:
    void add(void* a, void* b)
    {
        cout << "void add(void* a, void* b)" << endl;
        cout << "Error to add void* param..." << endl;
    }
};
*/
class Test_Void
{
public:
    void add(void* a, void* b)
    {
        cout << "void add(void* a, void* b)" << endl;
        cout << "Error to add void* param..." << endl;
    }
};

int main()
{
    Test<int, float> t1;
    Test<long, long> t2;
    //Test<void*, void&> t3;
   
    Test_Void t3; //采用了重定义模板,写代码会考虑用特化还是重定义,后期维护不好
    
    t1.add(1, 2.5);
    
    t2.add(5, 5);
    t2.print();
    
    t3.add(NULL, NULL);
    
    Test<int*, double*> t4;
    int a = 1;
    double b = 0.1;
    
    t4.add(&a, &b);
    
    return 0;
}

注意:能用特化用特化,别混用。

 

编程实验
特化的深入理解
59-2.cpp
#include <iostream>
#include <string>

using namespace std;

template
< typename T >
bool Equal(T a, T b)    //函数模板
{
    cout << "bool Equal(T a, T b)" << endl;
    
    return a == b;    //不能用来比较两个浮点数相等。解决办法:函数模板特化
}

template    //函数模板完全特化——显示声明
< >
bool Equal<double>(double a, double b)    //浮点数精度不够。完全特化
{
    const double delta = 0.00000000000001;
    double r = a - b;
    
    cout << "bool Equal<double>(double a, double b)" << endl;
    
    return (-delta < r) && (r < delta);    //用这种方式判断两个数相等
}

int main()
{  
    cout << Equal( 1, 1 ) << endl;    //函数模板
    cout << Equal<double>( 0.001, 0.001 ) << endl;

    return 0;
}

操作:

1) g++ 59-2.cpp -o 59-1.out编译正常,打印结果:

bool Equal(T a, T b)
1
bool Equal<double>(double a, double b)
1

2) 定义重载函数:

#include <iostream>
#include <string>

using namespace std;

template
< typename T >
bool Equal(T a, T b)    //函数模板
{
    cout << "bool Equal(T a, T b)" << endl;
    
    return a == b;    //不能用来比较两个浮点数相等。解决办法:函数模板特化
}

template    //函数模板完全特化——显示声明
< >
bool Equal<double>(double a, double b)    //浮点数精度不够。完全特化
{
    const double delta = 0.00000000000001;
    double r = a - b;
    
    cout << "bool Equal<double>(double a, double b)" << endl;
    
    return (-delta < r) && (r < delta);    //用这种方式判断两个数相等
}

bool Equal(double a, double b)    //函数
{
    const double delta = 0.00000000000001;
    double r = a - b;
    
    cout << "bool Equal(double a, double b)" << endl;
    
    return (-delta < r) && (r < delta);
}

int main()
{  
    cout << Equal( 1, 1 ) << endl;    //函数模板
    cout << Equal( 0.001, 0.001 ) << endl;  
    return 0;
}

打印结果:

bool Equal(T a, T b)
1
bool Equal(double a, double b)
1

分析:编译器会优先选择重载的全局函数,放弃了特化。

 

改变编译器行为,让它使用模板特化:

int main()
{  
    cout << Equal( 1, 1 ) << endl;    //函数模板
    cout << Equal<>( 0.001, 0.001 ) << endl;  //加上<>,让编译器先匹配特化
    return 0;
}

打印结果:

bool Equal(T a, T b)
1
bool Equal<double>(double a, double b)
1

 

四、工程中的建议(编码原则)

            当需要重载函数模板时,优先考虑实验模板特化;   

            当模板特化无法满足需求,再使用函数重载!

 

小结

1)类模板可以定义任意多个不同的类型参数

2)类模板可以被部分特化完全特化

3)特化的本质是模板的分开实现

4)函数模板只支持完全特化

5)工程中使用模板特化代替类(函数)重定义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值