参考读物:
《Thinking in C++: vol1 & vol2》 Bruce Eckel - wwwbruceeckelcom
《C++ Template》 David Vandevoorde, Nicolai M Josuttis
推荐读物:
《modern C++ design》Andrei Alexandrescu
1 介绍
模板是一个包含有未指定类型的函数或类,因此模板并不是一个真正的函数或类,而是代表了一组函数或类,当为模板函数或类指定了一种类型时,就生成了此模板的一个实例,这个 *** 作叫做模板实例化(instantiation)。也可以为某一种类型提供不同于模板的定义,这个称为特化定义(specialization)。对于有多个类型参数的模板,还可以只指定一部分类型,这个称为偏特化定义(partial specialization)。
模板不是实体,因此模板的声明和定义通常都放在头文件中。
2 函数模板
21 声明
template<class T>
inline void func(T param)
{
}
22 函数模板不支持默认类型参数,但支持函数的默认参数
template<class T/ = type,不可以 />
void func(T param, int size = sizeof(T))
{
}
23 函数模板显式实例化声明
template void func<int>(int param);
显式实例化后的函数模板不能再有不能转换的类型的调用
显式实例化后的函数模板不能被特化定义
24 特化定义函数模板
template<>
void func<int>(int param) //函数模板只支持全特化
{
}
特化后是一个实体函数,不再是模板,放在头文件中会导致重定义
25 函数模板重载
template<class T>
void func(T param, int i)
{
}
template<>
void func(ClassName param, int i)
{
}
void func(int i)
{
}
这几种func函数的定义,匹配的顺序是非模板函数 -> 特化函数模板 -> 基函数模板。如果不像func<int>(100)这样指定函数模板的参数类型的话,编译器会为函数模板推测出一种类型,如根据100为int类型,编译器会自动调用func<int>,称为隐式特化,而前者则成为显式特化。
为什么函数模板要特化呢?这是因为有时候函数模板并不能处理所有情况,对于个别情况就可以使用特化来替换掉原来模板。
3 类模板
31 声明
template<class T>
class ClassName
{
};
32 类方法类外定义
template<class T>
ReturnType ClassName<T>::Func()
{
};
33 非类型(nontype)模板参数
如template<size_t _Nb> class bitset {}就是使用size_t类型参数设置位的个数。
可以是常量整数类型(包括枚举)或外部链接(external linkage)对象的指针或引用作为模板参数,不能是浮点型和类对象。
char s = "hello"; //s不可以,直接使用"hello"亦不可以,因为两个"hello"可能为不同地址
char s[] = "hello"; //s可以
ClassName obj; //obj可以
ClassName<int> obj; //obj可以
什么是一个外部链接对象呢?
关于这个问题,专门转载了SpitFire同志的一篇文章《内部链接和外部链接》到博客中
总的说来,要作为参数必须满足:1、在编译时和链接时可以求值; 2、这个参数如果是指针,则它所指的变量,如果在两个cpp中定义会出链接错误。
不同的参数值构成不同的类型,bitset<100>和bitset<200>是两个类型
34 默认参数
template<class T = int, int param = 100>
class ClassName
{
};
35 以模板为类型参数的类模板声明
template<class T>
class Array;
template<class T1, template<class / 可以省略类型名 / > class T2>
class ClassName
{
T2<T1> m_o;
}
如果T2是带默认参数的:template<class U, int i = 100> class T2; 则在以它为类型参数的类中必须再次指明默认值,如果两个默认值不同以再次声明的为准。
template<class T, int i = 100>
class Array;
template<class T1, template<class, int = 100> class T2>
class ClassName
{
T2<T1> m_u;
}
使用:
ClassName<int, Array> obj;
36 特化模板类
template<class A, class B>
class ClassName
{
};
361 全特化
template<>
class ClassName<int, double>
{
}; //特化后是一个实体类,不再是模板
362 偏特化
template<class B>
class ClassName<int, B>
{
}; //特化后是一个实体类,仍是模板
template<class A, class B>
class ClassName<A, B>
{
};
363 类成员函数特化
template<class T>
class ClassName
{
public: void f();
};
template<>
inline void class ClassName<int> :: f()
{
} //特化类ClassName<int>的f(),T为int类型时优先调用此定义
37 模板类里的静态变量
template<class T>
class ClassName
{
static T a;
}
定义:
int ClassName<int>::a = 100; / 定义一个与类模板的类型参数对应的静态变量 /
main()
{
ClassName<int> o;
}
38 typename关键词
381 表明紧跟在后面的是类型,而不是其他(如静态变量)
typename vector<T>::iterator it;
382 定义新类型
typedef typename vetor<T>::iterator Iterator_Type;
383 代替模板中的class关键词
template<typename T>
class ClassName
{
};
39 模板类中的成员函数模板
template<class T>
class ClassName
{
public:
template<class T1, class T2> T m_func(T1 a, T2 b);
}
类外定义:
template<class T>
template<class T1, class T2>
T ClassName<T>::m_func(T1 a, T2 b)
{
}
特化
template<>
template<>
int ClassName<int>::m_func(int a, int b) //类必须被一起全特化
{
}
调用:
ClassName<int> o;
otemplate m_func<int, vector<int> >(100, vector<int>()); //调用时实例化
310 继承模板类
template<class T>
class Chlid : public Parent<T>
{
};
3101 特化继承
class ClassName : public vector<int>
{
};
311 explicit关键字
explicit Y(const X& x);
X x; Y y(x); //显式转换
X x; Y y = x; //隐式转换,编译不通过
第一条语句通过使用显式从X类型转换生成了一个Y类型的对象,后一条语句则使用了隐式转换创建。由于使用了explicit要求必须使用显式,所以编译没有通过。
4 总结
模板加强了使用C++编写可复用代码的能力,但是想学好模板需要花费很大的功夫和精力的,而最难的就是将模板和原有C++面向对象的技术,如继承和多态等,相互融会贯通。
这个是c++中的模板
template
这个是定义模板的固定格式,规定了的
你上面的那个代码就是定义了一个模板函数
模板应该可以理解到它的意思吧
比如你想求2个int
float
或double型变量的值,只需要定义这么一个函数就可以了,假如不用模板的话,你就必须针对每种类型都定义一个sum函数
int
sum(int,
int);
float
sum(float,
float);
double
sum(double,
double);
模板函数可以化简工作量列入你要完成
列入你想完成 整形相加,浮点相加,
int add(int a,int b)
{return a+b;}
float add(float a,float b)
{return a+b}
double add(double a,int b)
{return a+b}
有多少相加你就得写多少函数如果用模板函数则只需一个函数就OK了
template<class T>//T代表任意类型
T add(T a,T b)
{return a+b}
template<class T,class T1>//T代表任意类型
T add(T a,T1 b)
{return a+b}
LZ这里粗心大意了:
//定义
template<class T>
void fun(Test<T> t) //模板类型要有模板参数列表
{
}
请注意一点,这里是在定义一个模板函数,而普通的友元函数声明只能声明一个特定的函数实例作为友元,比如声明friend void fun(Test t); 这是声明了一个普通函数作为友元,对于Test<int>而言,这个普通函数就是void fun(Test<int> t); 而又找不到函数void fun(Test<int> t)的定义(这里全局作用域中定义的模板函数并不会对应实例化),故会连接出错,有如下解决方案:
1:fun<int>(t);//此处显式实例化函数模板,这里并不需要ADL查找
2:将友元函数整个定义搬到模板类中,以使类的每个实例化均产生一个相应的友元函数,该友元函数需要通过ADL查找。
template<class T>
class Test
{
friend void fun(Test t)
{
}
};
3:声明一个模板函数作为友元,这时编译器知道fun(t)是在调用一个模板函数,故实例化相应版本。
template<class T>
class Test
{
template<class U>
friend void fun(Test<U> t);
};
模板虽早在80年代就以出现在C++中,但问题仍然不少,有很多技术或历史原因使其不易理解,我这里说的或许有问题,还请LZ多查资料才是。
另外,站长团上有产品团购,便宜有保证
函数的摸版就是函数定义的时候带有摸版功能但是没有实力化它只是一个空壳子,模版函数就是调用的时候这时给它传递了实力化的类型如<int>这时这个函数就称为模版函数了`因为这个函数是在模版上运行的`它让函数的模版有了实际的类型`就是在函数的模版上工作了`
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)