类模板深度剖析

  • 多参数类模板,类模板可以定义多个不同类型的参数
template
<typename T1,typename T2>
class Test
{
public:
    void add(T1 a,T2 b);
}
//使用方式
//需要指定每一个类型参数
//int  --->T1
//float--->T2
Test<int,float> t;
  • 令人惊讶的特性:类模板可以被特化
  1. 指定类模板的特定实现
  2. 部分类型参数必须显示指定
  3. 根据类型参数分开实现类模板
  4. 如下图所示,我们指定实际类型参数时,如果T1,T2是相同的类型,编译器会优先选择右边的类模板的实现,这两个类模板不会发生同名冲突的问题,编译器会把它们理解为同一个模板,只是根据类型参数来选择是使用哪一个模板。
 
  • 类模板的特化类型
  1. 部分特化---用特定规则约束类型参数(即使特殊了,参数仍然是一个泛指类型)
  2. 完全特化---完全显示指定类型参数
  3. 如下图所示为完全特化:如果要使用Test类模板的时候完全显示指定泛指类型T1,T2都为int的时候,编译器会选择使用右边的完全特化的类模板来实现。
 
  • 类模块特化注意事项
  1. 特化只是模块的分开实现,本质上是同一个类模块。
  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=" << a + b << endl;
        }
};
template <typename T>
//当Test类型参数完全相同时,使用这个类模板来实现
//编译器不会把它当成一个新的模板,只会把它看成Test模板的一种特殊的实现。
//部分特化
class Test<T, T>
{
public:
        void Add(T a, T b)
        {
               cout << "void Add(T a, T b)" << endl;
               cout << "a+b=" << a + b << endl;
        }
};
//当Test类型参数都为void*类型是,使用这个类模板来实现
//完全特化
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;
        }
};
//关于指针的特化实现
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=" << *a + *b << endl;
        }
};
int main()
{
        Test<int, float> t1;
        Test<long, long> t2;
        Test<void*, void*> t3;
        Test<int*, double*> t4;
        int a = 2;
        double b = 3.14;
        t1.Add(1,2.5);
        t2.Add(2,3);
        t3.Add(NULL,NULL);
        t4.Add(&a,&b);
}
  • 运行结果
void Add(T1 a,T2 b)
a+b=3.5
void Add(T a, T b)
a+b=5
void add(void* a,void* b)
Error to add void* Param
void Add(T1* a,T2* b)
*a+*b=5.14
  • 问题
  1. 类模板特化与重定义有区别吗?
  2. 函数模板可以特化吗?
  • 重定义和特化的不同
  1. 重定义:一个类模板和一个新类(或者两个类模板),使用的时候需要考虑如何选择的问题。
  2. 特化:以统一的方式使用类模板和特化类,编译器自动优先选择特化类 
  • 函数模板只支持类型参数完全特化
template <template T>
//函数模板定义
bool Equal(T a,T b)
{
    return a==b;
}
//函数模板完全特化
template < >
bool Equal<void*>(void* a,void* b)
{
    return a==b;
} 
  • 范例程序
// 函数模板特化实验.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <string>
using namespace std;
template <typename T1,typename T2>
bool Equal(T1 a,T2 b)
{
     cout << "bool Equal(T1 a,T2 b)" << endl;
    return a == b;
}
//函数模板完全特化
template <>
bool Equal<double>(double a,double b)
{
    const double  detla = 0.0000000000001;
    double r = a - b;
    cout << "bool Equal<double>(double a,double b)" << endl;
    return (-detla < r) && (r < detla);
}
bool Equal(double a,double b)
{
    const double  detla = 0.0000000000001;
    double r = a - b;
    cout << "bool Equal(double a,double b)" << endl;
    return (-detla < r) && (r < detla);
}
int main()
{
    //调用的是函数模板
    cout << Equal(1, 2) << endl;
    //默认调用全局函数
    cout << Equal(0.1,0.1) << endl;
    //调用特化后的函数模板
    cout << Equal<double>(0.2, 0.2) << endl;
    //带个<>号,告诉编译器放弃全局函数,使用函数模板
    cout << Equal<>(0.4, 0.5) << endl;
}
  • 运行结果
bool Equal(T1 a,T2 b)
0
bool Equal(double a,double b)
1
bool Equal<double>(double a,double b)
1
bool Equal<double>(double a,double b)
0
  • 工程中的建议
当需要重载函数模块时,优先考虑使用模板特化。
当模板特化无法满足需求时,再使用函数重载。
  • 小结
  1. 类模板可以定义任意多个不同的类型参数
  2. 类模板可以被部分特化和完全特化
  3. 特化的本质是模板的分开实现
  4. 函数模板只支持完全特化
  5. 工程中使用模板特化代替类(函数)重定义
 
 
posted @ 2020-02-07 21:16  认真做个普通人  阅读(227)  评论(0编辑  收藏  举报