大多数时侯,没有模板是万万不能的,但有些时候,模板也不是万能的,尤其是面对指针时,比如
template <typename T>
int compare(const T &v1, const T &v2)
{
if (v1 < v2) return -1;
if (v2 < v1) return 1;
return 0;
}
|
一个比较大小的函数模板,但如果我们传进的实参是 char型指针,意在比较两个字符串时,小问题来了,该函数会比较两个指针自身的内存地址,而不是它们所指向的东西。
模板特化在此出现了,template Specialization!
template <>
int compare<const char*>(const char* const &v1,
const char* const &v2)
{
return strcmp(v1, v2);
}
|
上面就是一个模板特化,注意到:
1.关键字
template 后面接一对
空的尖括号
<>,如果没有“template <>”,就成了重载函数了
2.再接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参
3.后面是函数形参表和函数体
4.特化的声明必须与对应的模板相匹配
5.与其他函数声明一样,应在一个头文件中包含模板特化的声明,然后使用该特化的每个源文件包含该头文件。
该特化必须在所想要的调用前出现,否则编译器则会实例化该模板,特化出现在对该模板实例的调用之后是错误的。
// define the general compare template
template <class T>
int compare(const T& t1, const T& t2) { /* ... */ }
int main() {
int i = compare("hello", "world");
}
// invalid program: explicit specialization after call
template<>
int compare<const char*>(const char* const& s1,
const char* const& s2)
{ /* ... */ }
|
这种情况就达不到想要的效果。
类模板的特化,其中有部分成员特化情况,有点晕,没看完,以后再看。
函数模板的重载:不仅可以定义有相同名字但形参数目或类型不同的多个函数模板,
也可以定义与函数模板有相同名字的普通非模板函数。
如果重载函数中既有普通函数又有函数模板,确定函数调用的步骤如下:
1.为这个函数名建立候选函数集合,包括:与被调用函数名字相同的任意普通函数;任意函数模板实例化,在其中,模板实参推断发现了与调用中所用函数实参相匹配的模板实参;
2.确定哪些普通函数是可行的
3.如果需要转换来进行调用,根据转换的种类排列可靠函数,调用模板函数实例所允许的转换是有限的
如果只有一个函数可选,就调用这个函数;
如果调用有二义性,从可行函数集合中去掉所有函数模板实例;然后重新排列去掉函数模板实例的可行函数,如果只有一个函数可选,就调用这个函数;否则有二义性。
如果有如下两个函数:
template <typename T> int compare(const T&, const T&);
int compare(const char*, const char*);
|
调用时 char *p1 = ch_arr1, *p2 = ch_arr2;
compare(p1, p2);
调用的是第一个函数模板的实例,因为到普通函数的参数转换还需将参数变为const;
欲调用普通函数就得 char
const*p1 = ch_arr1,
const *p2 = ch_arr2;
compare(p1, p2);
通常来讲,定义函数模板特化几乎总是比使用非模板版本更好。
阅读(945) | 评论(0) | 转发(0) |