C++11中的模板特例化

目录

函数模板特例化

类模板特例化


  最近在看智能指针的源码,发现其中用了很多模板特例化,本文就来总结一下,什么是模板特例化。

      特例化,顾名思义:特殊实例化,将函数模板或类模板实例化为特殊的类型,通过模板特例化可以定制在特定模板参数下的函数模板/类模板实现,或者禁用特定模板的函数模板/类模板

函数模板特例化

       既然是特例化,那么自然就需要有一个“原型”,现在假设一个原型模板函数compare,用来比较传入的两个参数的大小,如下所示:

template<typename T>
bool compare(T param1,T param2)
{
	return param1 < param2;
}

      通过这个模板函数,可以传入任意类型的两个参数,如compare(1,2); compare(1.1,2.1);

      那要是compare("hello","hey");呢?传入的两个参数类型为const char *类型的指针,这种情况如果还只是比较两个指针的大小,显然是不行的,应当使用strcmp来比较。所以,当模板参数类型为const char *类型时,这就需要进行“特例化”了,特例化compare如下所示:

template<>
bool compare(const char * str, const char * str2)
{
	cout << (str < str2) << endl;
	return strcmp(str, str2) < 0;
}

      由于前面只有一个模板参数T,特例化T后就没有模板参数了,所以在特例化模板函数中template 参数为空。这就相当于把原模板进行T = const char *的实例化,当T为const char *的时候就直接调用特例化的compare。需要注意的是,这里的特例化模板函数并不是模板重载,它一样是匹配原模板,只不过在T为const char *时使用特例compare。

 

       上面是模板参数全部特例化的例子,也可以进行部分特例化,如下所示:

template<typename T1, typename T2>
void fun(T1 param1, T2 param2)    //原模板
{
	cout << "orginal template" << endl;
}

template<typename T>
void fun(T param1, int param2)    //第二个参数为Int时的特例化模板
{
	cout << "special template" << endl;
}

int main
{
    fun(1,1.0);    //使用原模板函数
    fun(1,1);      //使用特例化模板函数
    return 0;
}

        特例化的一个好处就是可以在不能/不希望使用某些模板参数下的模板时,对其进行禁用。比如说上面的fun函数,我不希望第二个参数为int,那么就可以禁用这种特例化模板,这样当传入的第二个实参为int型时,编译器就会报错。

template<typename T1, typename T2>
void fun(T1 param1, T2 param2)    //原模板
{
	cout << "orginal template" << endl;
}

template<typename T>
void fun(T param1, int param2) = delete ;    //禁用第二个参数为Int时的特例化模板

/*   也可以只声明不定义
template<typename T>
void fun(T param1, int param2);
*/

int main
{
    fun(1,1.0);    //使用原模板函数
    fun(1,1);      //报错,编译器不通过
    return 0;
}

        在禁用特例化的情况下,fun(1,1)也没有去调用原模板函数,这也说明了特例化并非重载(如果是重载的话,那么就会直接调用第一个模板函数)。 

类模板特例化

      现在假定一个模板类A,接收两个模板参数,第二个模板参数为bool类型,现在将第二个模板参数为true进行特例化,如下所示:

template<class T,bool b>  //原模板
class My 
{
public:
	void fun()
	{
		cout << "original" << endl;
	}
};

template<class T>     //特例化第二个参数为true时相应的模板
class My < T, true >
{
public:
	void fun()
	{
		cout << "special" << endl;
	}
};

My<double,false> m;
m.fun();     //使用原模板  打印“original”

My<int,true>n;
n.fun();     //使用特例化模板  打印“speacial”

         上面这个例子其实就是unique_ptr源码中的一部分,参考_Unique_ptr_base模板特例化 。

         这只是特例化了一个模板参数,当然也可以把所有参数都特例化,在上面程序的基础上再加上如下代码:

template<>     //特例化两个模板参数
class My < int, true >
{
public:
	void fun()
	{
		cout << "special special" << endl;
	}
};

       这就相当于把原模板中的两个参数都进行了特例化,需要注意的是,此时如果再使用n.fun(),那么打印的结果则是“special  special”,可以看到,模板实例会优先匹配特例化程度更高的模板。

 

       和禁用某种模板下的函数模板相同,也可以禁用某种模板下的类模板。比如说我希望禁用第二个模板参数为true的模板,那么就可以对其进行不完整定义,如下所示:

template<class T>     //特例化第二个参数为true时相应的模板
class My < T, true >;  //不完整定义

My<int,true>n;  //编译出错
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章