模板的特化简单地理解就是明确参数的类型,而不是用 typename , 不管是函数模板,还是类模板,都可以实现特批。其语法为:template <> xxx,模板参数是空的。
一、函数模板的特化
如下最简单的一个函数模板特化:
#include <stdio.h>
#include <stdlib.h>
#include <typeinfo>
template <typename T>
void func(T a);
template<>
void func(int value)
{
printf("type of T is: int, value = %d\n", value);
}
int main()
{
int value = 10;
func(value);
return 0;
}
首先是声明了一个函数模板:
template <typename T>
void func(T a);
接下来就是特化这个函数模板,特化的参数类型就是 int 类型:
template<>
void func(int value)
{
printf("type of T is: int, value = %d\n", value);
}
假如我们使用 func(10.0)
#include <stdio.h>
#include <stdlib.h>
#include <typeinfo>
template <typename T>
void func(T a);
template<>
void func(int value)
{
printf("type of T is: int, value = %d\n", value);
}
int main()
{
int value = 10;
func(value);
func(10.0);
return 0;
}
则是编译错误的,提示我们没有实现对应类型 double 的模板:
因为我们上面只是声明了一个函数模板,同时特化了一个 int 类型的模板,所以这样只能使用特化的那个版本。那要用其他类型版本的,该如何操作呢?其实就是要声明时同时定义就可以:
#include <stdio.h>
#include <stdlib.h>
#include <typeinfo>
template <typename T>
void func(T a)
{
printf("type of T is: %s\n", typeid(T).name());
}
template<>
void func(int value)
{
printf("type of T is: int, value = %d\n", value);
}
int main()
{
int value = 10;
func(value);
func(10.0);
return 0;
}
只是把声明改成了实现:
template <typename T>
void func(T a)
{
printf("type of T is: %s\n", typeid(T).name());
}
实现使用时,int 类型参数使用了特化版本的函数,而 double 则使用普通版本的函数:
我们知道,模板只有在使用的时候才会生成对应类型的代码,如果只是声明或定义时,是不会生成相应代码的;而这个特化的模板是否有相应类型的代码呢?有如下代码:
#include <stdio.h>
#include <stdlib.h>
#include <typeinfo>
template <typename T>
void func(T a)
{
printf("type of T is: %s\n", typeid(T).name());
}
template<>
void func(int value)
{
printf("type of T is: int, value = %d\n", value);
}
int main()
{
int value = 10;
func(value);
return 0;
}
可以看到只有一个特化出来对应的 int 版本的代码。如果多加一行代码:func(10.0) ,结果会是什么样的呢?
可以看到多了一个 double 类型的模板代码。
二、类模板的特化
类模板的特化跟函数模板的特化相似的。
#include <stdio.h>
#include <stdlib.h>
template <typename T>
class S;
template<>
class S<int>
{
public:
void msg()
{
printf("fully specialized (S<void>::msg())\n");
}
};
int main()
{
S<int> test1;
test1.msg();
// S<void> test2; //这里若要正常使用,则上面的S声明必须要实现,因为S没有void版本的特化。
// test2.msg();
return 0;
}
代码里只是声明了类模板 S,同时特化了 int 类型的类模板,正如注释里说的要想使用 S<void> 的版本,则上面的必须是定义,而非声明。