5 - 模板重载,全特化和偏特化
本文简要介绍了函数模板的重载,类模板的全特化和偏特化等知识。
函数模板的重载
介绍
函数模板是可以重载的(类模板不能被重载),通过重载可以应对更加复杂的情况。
例如,在处理字符串对象时可以用两种形式来描述:char*
和string
。前者在复制时直接拷贝内存,效率高;而后者还得依次调用构造函数。因此,在一些追求效率的程序中,应对不同类型进行不同的处理。
使用
首先,我们创建一个函数函数及其重载:
// 函数模板
template<typename T>
void test(const T& param)
{
std::cout << "void test(const T& param)" << std::endl;
}
// 函数模板的重载
void test(double param)
{
std::cout << "void test(double param)" << std::endl;
}
发现它主要对double
类型进行了特殊处理,可以康康效果:
// 输出:void test(const T& param)
test(100);
// 输出:void test(double param)
test(100.0);
注意
需要注意的是:
如果显式指定函数模板的类型参数,那么用的就不是重载了:
// 输出: void test(const T& param) test<double>(100);
函数模板可以被特化(特化很快会说),但绝不推荐这样做,因为这样的函数模板特化不会参与重载解析,可能会出现意外的行为。
类模板的特化
类模板不能重载,但可以通过特化来实现与函数模板重载的类似功能。模板特化分为两种:
- 全特化:模板的实参列表与相应的模板参数列表一一对应
- 偏特化:介于普通模板和全特化之间,只存在部分类型明确化,而非将模板唯一化
使用
我们创建一个类模板,并对他进行偏特化和全特化:
template<typename T1, typename T2>
class Test
{
public:
Test() { std::cout << "common template" << std::endl;}
};
// 部分特化:指针版本
template<typename T1, typename T2>
class Test<T1*, T2*>
{
public:
Test() { std::cout << "point semi-special" << std::endl; }
};
// 部分特化: int, T2
template<typename T2>
class Test<int, T2>
{
public:
Test() { std::cout << "int semi-special" << std::endl; }
};
// 全特化:int, int
template<>
class Test<int, int>
{
public:
Test() { std::cout << "int, int comp-special" << std::endl; }
};
它的对应输出如下:
// point semi-special
Test<int*, int*> test1;
// int semi-special
Test<int, double> test2;
// int, int comp-special
Test<int, int> test3;
// common template
Test<int*, int> test4;
类模板特化最突出的一个应用就是类型的获取:
// 模板特化(解决从int*知道是int类型的指针)
template<typename T>
struct get_type
{
using type = T;
};
template<typename T>
struct get_type<T*>
{
using type = T;
};
// 使用例
data = new typename get_type<T>::type(*elem);
偏特化的特殊使用
接下来用模板偏特化实现std::is_same_v<T1, T2>
,它的作用是比较两类型是否相同。
template<class, class>
struct is_same
{
static constexpr bool value = false;
};
template<class Ty>
struct is_same<Ty, Ty>
{
static constexpr bool value = true;
};
int main()
{
// True
std::cout << std::boolalpha << is_same<int, int>::value << '\n';
// False
std::cout << std::boolalpha << is_same<int, unsigned>::value << '\n';
return 0;
}
这里的is_same<Ty, Ty>
是类模板偏特化的特殊使用方法,只有两个类型相同时才会执行这个特化,让value
为真。
参考资料
- 飘零的落花 - 现代C++详解
- C++20高级编程