1.模板简介
模板就是实现代码重用的一种机制,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。
模板编程和函数重载可以实现C++静态多态,也叫编译时多态。
模版可以分为两类,一个是 函数模版 ,另一个是 类模版。
2.模板特化的目的
模板本来是一组通用逻辑的实现,但是可能存在特定的参数类型下,通用的逻辑实现不能满足要求,这时就需要针对这些特殊的类型,而实现一个特例模板—即模板特化。
3.重点注意
1)类模板和函数模板都可以被全特化;
2)类模板能偏特化,不能被重载;
3)函数模板可以实现重载,不能被偏特化;
4)类模板调用优先级:全特化类>偏特化类>主版本模板类;
5)注意模板编程不支持分离式编译,即模板类/模板函数的声明与定义应该放在头文件里,否则会在链接时报错;
6)函数模板同时存在具体化模板、函数模板重载、和常规函数重载时候,调用优先级:
常规函数 > 具体化模板函数 > 常规模板函数;
注意:重载决议时,优先决议出是不是符合常规函数,不存在符合的普通函数,才会再决议出符合的函数主模板,对于函数模板重载决议,会无视特化存在(标准规定:重载决议无视模板特化,重载决议发生在主模板之间),决议出函数主模板后,如果函数主模板存在符合的具体化函数模板,才会调用具体化函数模板;
7)不能将函数模板特化和重载混为一谈
函数特化都没有引入一个全新的模板或者模板实例,它们只是对原来的主(或者非特化)模板中已经隐式声明的实例提供另一种定义。在概念上,这是一个相对比较重要的现象,也是特化区别于重载模板的关键之处。
如果使用普通重载函数,那么不管是否发生实际的函数调用,都会在目标文件中生成该函数的二进制代码。而如果使用函数模板特化版本,除非发生函数调用,否则不会在目标文件中包含特化模板函数的二进制代码。这符合函数模板的“惰性实例化”准则。
4.函数模板
1)常规函数
// 常规函数
void Compare(const char* first, const char* second)
{
cout << "const char* ordinary function " << endl;
if (strcmp(first, second) > 0) // 比较char*,需要区别函数主模板进行处理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
2)函数主模板a
//函数主模板
template<typename T, typename N> void Compare(T first, N second)
{
cout << "Standard function template <T, N>" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
3)函数模本b--全特化
针对char*类型的比较函数,不能直接使用大于号或小于号比较元素,需要特化;
//函数模板-全特化
template<> void Compare(const char* first, const char* second)
{
cout << "const char* specialization <const char*, const char*>" << endl;
if (strcmp(first, second) > 0) // 比较char*,需要区别函数主模板进行处理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
4)函数模板c-重载,作为一个独立的函数主模板
//函数模板-重载,不是偏特化,它会作为一个独立的函数主模板
template<typename T, typename N> void Compare(T* first, N* second)
{
cout << "function template overload <T*, N*>" << endl;
cout << "T type: " << typeid(T).name() << ", N type : " << typeid(N).name() << endl;
if (strcmp(typeid(T).name(), "char") == 0 && strcmp(typeid(N).name(), "char") == 0)
{
if (strcmp(first, second) > 0) // 比较char*,需要区别函数主模板进行处理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
else
{
if (*first < *second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
}
5)函数模板之间的重载决议
【1】当代码中存在如下顺序的申明时,
template<typename T, typename N> void Compare(T first, N second) //函数主模板a
{.....}
template<> void Compare(const char* first, const char* second) // 函数主模板a的全特化模板 b
{.....}
template<typename T, typename N> void Compare(T* first, N* second) // 函数主模板c,是函数主模板a的重载
{.....}
那么,发生如下函数调用时,
Compare("1", "2");
会打印输出:
这里显示实际调用了函数主模板c,
因为在调用Compare("1", "2")时,先会进行重载决议,
发生重载决议,会无视特化存在(标准规定:重载决议无视模板特化,重载决议发生在主模板之间),
那么就会决议出函数主模板c;
【2】当代码中存在如下顺序的申明时,
template<typename T, typename N> void Compare(T first, N second) //函数主模板a
{.....}
template<typename T, typename N> void Compare(T* first, N* second) // 函数主模板b,是函数主模板a的重载
{.....}
template<> void Compare(const char* first, const char* second) // 此时是函数主模板b的全特化模板 ,为全特化函数模板c
{.....}
那么,发生如下函数调用时,
Compare("1", "2");
会打印输出:
这里显示实际调用了全特化函数模板c,
因为在调用Compare("1", "2")时,先会进行重载决议,
发生重载决议,会无视特化存在(标准规定:重载决议无视模板特化,重载决议发生在主模板之间),
那么就会决议出函数主模板b,在判断函数主模板存在符合类型条件的全特化模板c
函数模板特化与重载决议
6)常规函数与函数模板之间的重载决议
当代码中存在如下顺序的申明时,
template<typename T, typename N> void Compare(T first, N second) //函数主模板a
{.....}
template<> void Compare(const char* first, const char* second) // 函数主模板a的全特化模板 b
{.....}
template<typename T, typename N> void Compare(T* first, N* second) // 函数主模板c,是函数主模板a的重载
{.....}
void Compare(const char* first, const char* second) // 常规函数
{.....}
那么,发生如下函数调用时,
Compare("1", "2");
会打印输出:
这里显示实际调用了常规函数,
因为在调用Compare("1", "2")时,先会进行重载决议,重载决议会优先决议是否存在符合条件的常规函数。
7)函数模板全部实现
/******************************* template function start ****************************************/
//函数主模板
template<typename T, typename N> void Compare(T first, N second)
{
cout << "Standard function template <T, N>" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
cout << endl;
}
//函数模板-全特化
template<> void Compare(const char* first, const char* second)
{
cout << "const char* specialization <const char*, const char*>" << endl;
if (strcmp(first, second) > 0) // 比较char*,需要区别函数主模板进行处理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
cout << endl;
}
//函数主模板-重载,不是偏特化,它会作为一个独立的函数主模板
template<typename N> void Compare(int first, N second)
{
cout << "partitial specialization <int, N>" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
cout << endl;
}
//函数模板-重载,不是偏特化,它会作为一个独立的函数主模板
template<typename T, typename N> void Compare(T* first, N* second)
{
cout << "function template overload <T*, N*>" << endl;
cout << "T type: " << typeid(T).name() << ", N type : " << typeid(N).name() << endl;
if (strcmp(typeid(T).name(), "char") == 0 && strcmp(typeid(N).name(), "char") == 0)
{
if (strcmp(first, second) > 0) // 比较char*,需要区别函数主模板进行处理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
else
{
if (*first < *second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
cout << endl;
}
//函数主模板-重载,不是偏特化,它会作为一个独立的函数主模板
template<typename T, typename N> void Compare(std::vector<T>& first, std::vector<N>& second)
{
cout << "to vector partitial specialization <std::vector,std::vector>" << endl;
if (first.size() < second.size())
{
cout << "first.size() < second.size()" << endl;
}
else
{
cout << "first.size() >= second.size()" << endl;
}
cout << endl;
}
// 常规函数
void Compare(const char* first, const char* second)
{
cout << "const char* ordinary function " << endl;
if (strcmp(first, second) > 0) // 比较char*,需要区别函数主模板进行处理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
cout << endl;
}
// 测试函数模板功能
void Test_Temmplate_Function()
{
cout << __FUNCTION__ << ":" << endl;
Compare(1,2);
Compare(1, 2.0);
Compare(1.0, 2.0);
Compare('1', '2');
Compare("1", "2");
vector<int> v1 = { 1 };
vector<int> v2 = { 2 };
Compare(v1, v2);
cout << endl;
}
/******************************* template function end ****************************************/
打印输出如下图,
5.类模板
必须先有泛化版本类模板(主模板),才有特化版本类模板。
1)类模板特化分类
特化为绝对类型(全特化);
特化为引用,指针类型(半特化、偏特化);
特化为另外一个类模板(复杂点的偏特化)
2)类模板-主模板类
//类模板-主版本模板类
template<typename T, typename N> class MyClass
{
public:
void Compare(T first, N second)
{
cout << "standard function template" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
3)类模板-全特化(具体化)
//类模板-全特化(具体化)
template<> class MyClass<const char*, const char*>
{
public:
void Compare(const char* first, const char* second)
{
cout << "const char* specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (strcmp(first, second) > 0) // 比较char*,需要区别函数主模板进行处理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
};
4)类模板-特化(部分具体化),对部分模板参数进行特化为一般类型
//类模板-特化(部分具体化),对部分模板参数进行特化
template<typename N> class MyClass<int, N>
{
public:
void Compare(int first, N second)
{
cout << "partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
5)类模板-特化(部分具体化),将模板参数特化为指针
//类模板-特化(部分具体化),将模板参数特化为指针
template<typename T, typename N> class MyClass<T*, N*>
{
public:
void Compare(T* first, N* second)
{
cout << "ptr partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
6)类模板-特化(部分具体化),将模板参数特化为另一个模板类
//类模板-特化(部分具体化),将模板参数特化为另一个模板类
template<typename T, typename N> class MyClass<vector<T>, vector<N>>
{
public:
void Compare(const vector<T>& first, const vector<N>& second)
{
cout << "to vector partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first.size() < second.size())
{
cout << "first.size < second.size" << endl;
}
else
{
cout << "first.size >= second.size" << endl;
}
}
};
7)类模板特化全部实现
/******************************* template class start ****************************************/
//类模板-主版本模板类
template<typename T, typename N> class MyClass
{
public:
void Compare(T first, N second)
{
cout << "standard function template" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
//类模板-全特化(具体化)
template<> class MyClass<const char*, const char*>
{
public:
void Compare(const char* first, const char* second)
{
cout << "const char* specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (strcmp(first, second) > 0) // 比较char*,需要区别函数主模板进行处理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
};
//类模板-特化(部分具体化),对部分模板参数进行特化
template<typename N> class MyClass<int, N>
{
public:
void Compare(int first, N second)
{
cout << "partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
//类模板-特化(部分具体化),将模板参数特化为指针
template<typename T, typename N> class MyClass<T*, N*>
{
public:
void Compare(T* first, N* second)
{
cout << "ptr partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
//类模板-特化(部分具体化),将模板参数特化为另一个模板类
template<typename T, typename N> class MyClass<vector<T>, vector<N>>
{
public:
void Compare(const vector<T>& first, const vector<N>& second)
{
cout << "to vector partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first.size() < second.size())
{
cout << "first.size < second.size" << endl;
}
else
{
cout << "first.size >= second.size" << endl;
}
}
};
// 测试类模板功能
void Test_Temmplate_Class()
{
cout << __FUNCTION__ << ":" << endl;
MyClass<char, int> c_i_myclass;
c_i_myclass.Compare(1, 2);
printf("function address: %p\n\n", &MyClass<char,int>::Compare);
MyClass<int, double> i_d_myclass;
i_d_myclass.Compare(1, 2);
printf("function address: %p\n\n", &MyClass<int, double>::Compare);
MyClass<int, int> i_i_myclass1;
i_i_myclass1.Compare(1, 2);
printf("function address: %p\n\n", &MyClass<int, int>::Compare);
MyClass<int, int> i_i_myclass2;
i_i_myclass2.Compare(1, 2);
printf("function address: %p\n\n", &MyClass<int, int>::Compare);
MyClass<const char*, const char*> c_c_c_c_myclass;
c_c_c_c_myclass.Compare("1", "2");
printf("function address: %p\n\n", &MyClass<const char*, const char*>::Compare);
MyClass<vector<int>, vector<char>> vc_i_vc_c_maclass;
vc_i_vc_c_maclass.Compare({ 1 }, { 1,2 });
printf("function address: %p\n\n", &MyClass<vector<int>, vector<char>>::Compare);
cout << endl;
}
/******************************* template class end ****************************************/
执行后打印输出如下图所示,
可以看到MyClass<int, int>类型声明的对象,函数Compare地址是一样的。