您的位置:首页 > 编程语言 > C语言/C++

c++模版的一些使用方法(一)

2012-04-16 16:23 127 查看
在一个项目中,我认为c++模版的主要应用是对一些基础组件的封装。因为基础组件往往是供上层开发人员使用的,并且它一般具有不确定性和支持的旷阔性,stl的容器是个很好的例子。容器支持n中类型,这表现了它的广阔性,它又可以通过顺序和链式实现,这表现了不确定性。我把这些“重量级”的应用认为是模版的主要应用。

此外,有使用技巧的人也会通过使用模版来“耍一些小聪明”,这指的是通过模版简单化很多工作。

这里记一下我认为模版比较有用的基础特性:

1.带默认类型或默认参数的模版

example:

template<class T, int size=100>//将size的默认值设为100
class MyArr
{
T arr[size];
};

MyArr<int, 10> arr;
MyArr<int> arr1;//实例化模版时如果没有指定size,将使用默认值


或者模版也可以是带默认类型

example:

template<class T = int>//默认类型是int
class MyArr
{
T* p;
};

MyArr<float> da;//实例化出float类型
MyArr<int> di;//实例化出int类型
MyArr<> dd;//不指定类型,使用默认的int类型,效果和上面一行相同


2.模版的特化和偏特化

模版用于泛型,它指的是提供一个通用的框框,这个框框可以支持各种各样的类型,但重要的是这些各种各样的类型在模版内部所走的流程是一致的,但是可能会在使用中有这样的需求:

我希望在这各种各样的类型中,某几种类型的处理方式区别于其他大多数类型。

这就需要使用模版的特化或偏特化,任何一组特化或偏特化都是该模版所有可能实例化出的类型的一个子集。

example:

//模版的全集定义
template<class T,class P>
class AClass
{
public:
int x;
void print()
{
printf("%d\n",x);
}
};

//某一个子集:第二个类型为double,一种偏特化
template<class T>
class AClass<T,double>
{
public:
int x;
void print()
{
printf("specialize for double ---%d\n",x);
}
};

//某一个子集:第一个类型为float,第二个类型为double,一种特化
template<>
class AClass<float,double>
{
public:
int x;
void print()
{
printf("specialize for float & double ---%d\n",x);
}
};

AClass<int,char> a;
a.print();
AClass<int,double> b ;//使用偏特化来实例化
b.print();
AClass<float,double> c;//使用特化来实例化
c.print();
AClass<double,double> d;//注意这里,这里使用偏特化来实例化,而不是使用全集定义来实例
d.print();
output:



模版特化和偏特化的应用:

应用一:建立类似防火墙的黑名单\白名单机制

意思就是对于一个泛型,建立类型过滤,只允许一部分类型使用该模版

下面的例子将允许int和char类型实例化该模版

//模版全集
template<class T>
class WhiteList
{
public:
void print()
{
printf("123\n");
}
};

//特化int
template<>
class WhiteList<int>;//不实现

//特化char
template<>
class WhiteList<char>;//不实现

int _tmain(int argc, _TCHAR* argv[])
{
WhiteList<bool> b;
b.print();
WhiteList<char> c;//编译通不过
c.print();
WhiteList<int> i;//编译通不过
i.print();
WhiteList<double> d;
d.print();
return 0;
}


应用二:修改第三方库的代码

假设现在有这样一种需求A,可以通过使用某开源库B中的某个模块C实现,模块C在文件C.h中定义并实现,它是一个模版类型的类d,我们只需要include<c.h>就可以在自己的代码中使用类d定义对象了。但是使用的过程中发现,C中有部分代码和我们的需求有小小的偏差,那么该怎么办。可能最直接的办法是修改c.h,但是问题是,c.h并不是我们自己的代码,直接修改第三方库,有可能会对其他项目的使用造成影响。那么怎么办呢?

如果注意到类d是模版类型的,那么就有办法了。既然是模版类型,那么我们就可以在自己的代码中特化这个模版类,特化出我们需要的那个子集,这样,我们就必须在自己的代码中重新写一遍这个特化的模版,然后我们就可以在这里做一些小小的修改。

下面的例子中,第三方开源库B的c.h文件的模版类d中的print函数中,会在最后输出一个回车换行,但是我们实际使用时并不想有这个回车换行。那么就可以通过特化该模版来干掉这个回车换行。

使用模版特化修改前:

//-------第三方开源库B中的c.h
template<class T,class P>
class aClass
{
//.........
public:
void print()
{
printf("123456\n");
printf("\n");//这里有一个回车换行
}
};

//-------自己的代码
int _tmain(int argc, _TCHAR* argv[])
{
aClass<int,bool> a;
a.print();
return 0;
}




使用模版特化修改代码,去掉最后的回车换行:

//-------第三方开源库B中的c.h
template<class T,class P>
class aClass
{
//.........
public:
void print()
{
printf("123456\n");
printf("\n");
}
};

//-------自己的代码
template<>
class aClass<int,bool>//特化为我们需要的子集
{
//....其他的都不修改
public:
void print()
{
//只修改这里
printf("123456\n");
//printf("\n");去掉
}
};
int _tmain(int argc, _TCHAR* argv[])
{
aClass<int,bool> a;
a.print();
return 0;




其实就是编译器以最强匹配原则来找该模版实例化后的类型定义,他认为

template<>

class aClass<int,bool>



template<class T,class P>

class aClass

的匹配度高,所以就用前者了

需要注意的是,当你在另一个文件中做特化时(在使用开源库时,一定是include了别人的头文件,然后在自己的文件中特化),编译连接时就会在多个obj(起码是两个吧...)中出现该模版类的定义,这时会出现link错误,这是很正常的,只需要把特化的类声明成inline即可。(上面例子我省事直接把模版的全集定义也写在当前文件中了,所以特化那就不用inline了)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: