一、类模板特化
二、函数模板特化
特化: 模板是泛化的表现,可以指定不同类型做相同的表现。而特化是指对于某些特殊的类型(类型模板参数),进行特殊的处理。需要注意的是,必须先有了泛化版本,才会有对应的特化版本。
一、类模板特化
1、类模板全特化
a) 常规类模板全特化
- 全特化版本,即所有【类型模板参数】都被指定
- 全特化版本可以有多个【类型模板参数】不同的版本
- 编译器会优先选择满足条件的特化版本
#include <iostream>
using namespace std;
// 泛化版本
template<typename T, typename U>
class Test{
public:
Test()
{
cout << "Test<T, U>()" << endl;
}
};
// 全特化版本,即所有类型模板参数都被指定
template<>
class Test<int, int>{
public:
Test()
{
cout << "Test<int, int>()" << endl;
}
};
// 全特化版本可以有多个【类型模板参数】不同的版本
template<>
class Test<double, double>{
public:
Test()
{
cout << "Test<double, double>()" << endl;
}
};
int main()
{
// 编译器会优先选择满足条件的特化版本
Test<char, char> t1;
Test<int, int> t2;
Test<double, double> t3;
return 0;
}
- 全特化类模板的成员函数,必须放在类内定义,不然会报错(关于这一点,我也觉得很蛋疼,但是暂时没有找到很好的支持这一现象的原因说明)`(>﹏<)′
正确写法:
template<>
class Test<int, int>{
public:
Test()
{
cout << "Test<int, int>::Test()" << endl;
}
// 特化版本成员函数需要在类内实现
void Func()
{
cout << "Test<int, int>::Func()" << endl;
}
};
错误写法:
template<>
class Test<int, int>{
public:
Test()
{
cout << "Test<int, int>::Test()" << endl;
}
void Func();
};
template<>
void Test<int, int>::Func()
{
cout << "Test<int, int>::Func()" << endl;
}
报错信息:
[Error] template-id 'Func<>' for 'void Test<int, int>::Func()' does not match any template declaration
b) 特化成员函数
- 只对类模板中的【某些成员函数】进行特化
- 特化的成员函数,其被构造的对象依然是【泛化版本】的,但是会调用到【特化的成员函数】。
#include <iostream>
using namespace std;
// 泛化版本
template<typename T, typename U>
class Test{
public:
Test()
{
cout << "Test<T, U>()" << endl;
}
void Func();
};
// 泛化版本成员函数
template<typename T, typename U>
void Test<T, U>::Func()
{
cout << "Test<T, U>::Func()" << endl;
}
// 特化成员函数
template<>
void Test<int, int>::Func()
{
cout << "Test<int, int>::Func()" << endl;
}
int main()
{
Test<char, char> t1;
t1.Func();
Test<int, int> t2;
t2.Func();
return 0;
}
2、类模板偏特化
a) 模板参数数量 —— 偏特化
- 偏特化的特化参数类型可以跳着来,不一定需要从最右边开始(但是从代码风格来说,不建议这样做)
- 偏特化类模板,可以在类外进行成员函数的定义。(所以当一定需要将特化的类模板的成员函数【声明】和【定义】分开时,可以加一个无用的模板参数类型,凑成偏特化。但是我觉得这样做依然很蛋疼(っ °Д °;)っ)
// 模板参数数量 —— 偏特化
template<typename U>
class Test<int, U, int>{
public:
Test()
{
cout << "Test<int, U, int>::Test()" << endl;
}
void Func();
};
template<typename U>
void Test<int, U, int>::Func()
{
cout << "Test<int, U, int>::Func()" << endl;
}
b) 模板参数范围 —— 偏特化
- 范围的概念是说,从任意类型T,缩小为某种更小的范围T。
比如:从 int 变成 const int
从 T 变成 T*,或者变成T&(左值引用),或者变成T&&(右值引用)都是范围缩小。 - 编译器在选择特化版本时,会根据<>内的类型寻找最合适的版本
如下的 const T* 实际上是指向 const T 类型的指针,特化时会使用 <T* > 版本
而 T* const 实际上只读的指针,不可修改指向,更符合<const T>特化版本
// 模板参数范围 —— 偏特化
template<typename T>
class Test{
public:
Test()
{
cout << "Test<T>::Test()" << endl;
}
void Func();
};
template<typename T>
void Test<T>::Func()
{
cout << "Test<T>::Func()" << endl;
}
// const 特化版本
template<typename T>
class Test<const T>{
public:
Test()
{
cout << "Test<const T>::Test()" << endl;
}
void Func();
};
template<typename T>
void Test<const T>::Func()
{
cout << "Test<const T>::Func()" << endl;
}
// 指针* 特化版本
template<typename T>
class Test<T*>{
public:
Test()
{
cout << "Test<T*>::Test()" << endl;
}
void Func();
};
template<typename T>
void Test<T*>::Func()
{
cout << "Test<T*>::Func()" << endl;
}
int main()
{
Test<char> t1;
t1.Func();
Test<const char> t2;
t2.Func();
Test<char*> t3;
t3.Func();
Test<const char*> t4; // <T*> 特化版本
t4.Func();
Test<char* const> t5; // <const T> 特化版本
t5.Func();
return 0;
}
二、函数模板特化
a) 函数模板全特化
- 全特化函数模板,实际上等价于实例化一个函数模板,并不能看作函数重载。
- 即存在重载函数,又存在特化函数模板时,编译器会优先顺序为:
普通函数(重载函数)> 特化版本函数模板 > 泛化版本函数模板
// 函数模板泛化版本
template<typename T, typename U>
void Func(T val1, U val2)
{
cout << "Func<T, U>" << endl;
}
// 函数模板全特化版本
template<>
void Func<double, double>(double val1, double val2)
{
cout << "Func<double, double>" << endl;
}
int main()
{
Func('a', 'b');
Func(1.0, 2.0);
return 0;
}
b) 函数模板偏特化
- 实际上,函数模板是不允许被偏特化的(也是没有找到具体不允许偏特化函数模板的原因……○| ̄|_ =3)
错误写法:
// 函数模板偏特化版本(不被允许)
template<typename T>
void Func<T, double>(T val1, double val2)
{
cout << "Func<T, double>" << endl;
}
报错信息:
[Error] function template partial specialization 'Func<T, double>' is not allowed
模板定义、实现,建议都放在一个 .h 文件中。
同样,模板的泛化版本和特化版本建议放在一个 .h 文件中。
并且,应该让泛化版本放置于特化版本之前。
网友评论