模板的特化(具体化)
重点注意
1)类模板和函数模板都可以被全特化;
2)类模板能偏特化,不能被重载;
3)函数模板可以实现重载,不能被偏特化;
4)类模板调用优先级:全特化类>偏特化类>主版本模板类;
6)函数模板同时存在具体化模板、函数模板重载、和常规函数重载时候,调用优先级:
常规函数 > 具体化模板函数 > 常规模板函数;《这不是比较顺序,而是优先级》
注意:重载决议时,优先决议出是不是符合常规函数,不存在符合的普通函数,才会再决议出符合的函数主模板,对于函数模板重载决议,会无视特化存在(标准规定:重载决议无视模板特化,重载决议发生在主模板之间),决议出函数主模板后,如果函数主模板存在符合的具体化函数模板,才会调用具体化函数模板;
7)不能将函数模板特化和重载混为一谈
函数特化都没有引入一个全新的模板或者模板实例,它们只是对原来的主(或者非特化)模板中已经隐式声明的实例提供另一种定义。在概念上,这是一个相对比较重要的现象,也是特化区别于重载模板的关键之处。
如果使用普通重载函数,那么不管是否发生实际的函数调用,都会在目标文件中生成该函数的二进制代码。而如果使用函数模板特化版本,除非发生函数调用,否则不会在目标文件中包含特化模板函数的二进制代码。这符合函数模板的“惰性实例化”准则。
8>特化可以改变函数体
函数模板
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;
那将会调用函数主模板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)函数模板全部实现
#include<iostream>
using namespace std;
#include<string.h>
#include<vector>
/******************************* 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 ****************************************/
int main()
{
Test_Temmplate_Function();
}
//输出结果
Test_Temmplate_Function:
partitial specialization <int, N>
first < second
partitial specialization <int, N>
first < second
Standard function template <T, N>
first < second
Standard function template <T, N>
first < second
const char* ordinary function
first:1 <= second:2
to vector partitial specialization <std::vector,std::vector>
first.size() >= second.size()
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 ****************************************/
运行结果
Test_Temmplate_Class:
standard function template
Compare:
first < second
function address: 0x5581ffb2399c
partitial specialization
Compare:
first < second
function address: 0x5581ffb23a84
partitial specialization
Compare:
first < second
function address: 0x5581ffb23b76
partitial specialization
Compare:
first < second
function address: 0x5581ffb23b76
const char* specialization
Compare:
first:1 <= second:2
function address: 0x5581ffb23834
to vector partitial specialization
Compare:
first.size < second.size
function address: 0x5581ffb23e8e
此外,特化的模板只在传入特定的参数时才会调用,否则调用主模板
//模板操作自定义类型:方法一采用重载函数,将<<重载为友元函数,能访问保护成员。也能打印对象
#include <iostream>
#include<string.h>
using namespace std;
template<class T>
void print(T object)
{
cout<<object<<endl;
cout<<" choose_this "<<endl;
}
class point
{
friend void print<point>(point object);
protected:
int x;
int y;
string name;
//改正方法
public:
point(int x, int y,string name):x(x),y(y),name(name){};
};
template<>
void print<point>(point object)
{
cout<<object.x<<" "<<object.y<<" "<<object.name<<endl;
cout<<" choose_that "<<endl;
}
int main()
{ print(255);
cout<<"*****************************"<<endl;
point pp(11,22,"x and y");
//隐式调用
print (pp);
}
调用结果
255
choose_this
*****************************
11 22 x and y
choose_that
特化的模板只有特定的参数才能被调用,否则不会