C++模板的特化 (二)
onst char* t1,const char* t2)
{
return (strcmp(t1,t2) < 0) t2 : t1;
}
但是你不能这么搞:
template <>
bool mymax(const char* t1,const char* t2)
{
return (strcmp(t1,t2) < 0);
}
其实对于mymax这个模板函数的定义而言,是用一个模板参数控制了三个地方,那么你在特化的时候,就也需要用一个特定的类型修改那三处相应的地方,如果你非要返回bool,那么你只能再定义一个函数模板了:
template
bool mymax(const T t1, const T t2)
{
return t1 < t2 t2 : t1;
}
问题又来了,大家都知道函数重载是不关心返回值的,而只关心参数个数以及类型是否不一致,不一致就是重载,但是对于模板函数而言,这个规矩不再成立,因为任何与模板相关的东西都只是个架子放在那里而已,只要它符合语法规则就可以了,这些架子只是在有人要调用它们时才会发挥效力,也就是说,在编译的时候会为你搜寻合适的模板函数或者类,只要能找到就ok了,而且还要求是只找到一个,要是找到多个也不行,呵呵。
其实,对于函数而言,虽然不能偏特化,即不能再在函数名字后面像模板类一样搞个出来,但是可以通过函数的重载(注意这里说的重载是指的模板重载,而不是普通意义的函数重载)变通的实现偏特化:
template
bool mymax(T1 t1, T2 t2)
{
return t1 < t2 t2 : t1;
}
template
bool mymax(T1 t1, int t2)
{
return t1 < t2 t2 : t1;
}
再谈谈函数模板参数的推导,大致有以下几种方法,但是不管怎么推导,都必须得保证在调用函数前能确定模板函数的各个模板参数的类型。
template
T2 fun(T1 arg1, int arg2)
{
T2 t2;
return t2;
}
对于上面这种比较特殊的模板函数,你不能通过传递参数来自动得到所有模板参数的类型,因此你必须显示的指定T1和T2的类型,有两种方法可以实现此目的:
int (*pfun)(double,int) = fun;//借用函数指针定义
cout<
cout<(11, 3.2)<
如果上述模板函数改为:
template
T2 fun(T1 arg1, T2 arg2)
{
return arg2;
}
那么除了上述两种指定模板参数类型的方法之外,由于该模板函数参数的类型都可以借由其参数获得,因此我们省去指定模板参数这一步骤,而直接调用该模板函数:
fun(23, 2.3);
最后,再谈谈非类型模板参数的问题,在《C++ Template》的第四章有介绍。
template struct stack {...};
template int add(int x){return x+margin;}
上面两个例子分别对应了类和函数两种情形,有人说非类型的模板参数存在得毫无价值,实则不然,因为我们可以借由一个确定的数值来产生一种新的类型或者新的函数。对于上面两个例子,我觉得用非类型模板参数就很有意义,分别实现了让用户指定stack的大小以及指定需要增加的边际值,关于更多这方面的应用,大家可以在今后的开发过程中逐步发掘,此外,还很有必要强调一下对非类型模板参数的限制,不能使用浮点数、class类型的对象和内部链接对象(例如字符串常量"hello world!")作为实参;它们可以是常整数(包括枚举值)或者指向外部链接对象的指针。
对外部链接对象的指针举个例子:
template
class MyClass {...};
extern char const s[] = ”hello”;
MyClass x; //OK
好了,模板这块内容我先将这么多。
又从网上搞到点好东东,也贴在这里吧:
类模板:
* 如果类模板中含有静态成员,那么用来实例化的每种类型,都会实例化这些静态成员。
* 两个靠在一起的模板尖括号( > ) 之间需要留个空格,否则,编译器将会认为是在使用operator>>,导致语法错误。
* 特化的实现可以和基本类模板的实现完全不同。
* 类模板可以为模板参数定义缺省值,称为缺省模板实参,并且他们还可以引用之前的模板参数。
* 成员函数模版不能被声明为虚函数。
* 类模板不能和另外一个实体共享一个名称。
eg:
1 int C;
2
3 class C; // ok,
4
5 int X;
6
7 template < typename T >
8
9 class X; // error. 和变量X冲突
非类型模板参数:
在编译期或链接期可以确定的常值。这种参数的类型必须是下面的一种:
a> 整型或枚举
b> 指针类型( 普通对象的指针,函数指针,成员指针 )
c> 引用类型( 指向对象或者指向函数的引用 )
其他的类型目前都不允许作为非类型模板参数使用
今天又突然挖掘出来点好东东,贴在这里:
template
void f(t t) {} //f1
template <>
void f(int t) {} //f2
void f(int t) {} //f3
void f(char t) {} //f4
f(3); //invoke f3
f('3'); //invoke f4
/**
caveat: f3 must be put after f2, or an error occurs: specialization of void f(T) [with T = int] after instantiation;
notes: the compiler will use f3 as the instantiation for f1, and use f2 as the specialization for f1;
rule: specialization must be before instantiation (*);
Above we have discuss the template function, and then we'll focus on member template function.
acronym: MTF(member template function);
Firstly, you should pay attention to the rule: the specialization of MTF must be the outside of the class, i.e., inline should not be allowed.
Secondly, specialization and instantiation still follow t