这一学期给自己定的计划,其中之一就是学习泛型编程,这篇文章也算是这个计划的开山之作吧,以后有什么心得体会也会在这里跟大家分享。
至于我本人,水平实在不咋滴= =
问:给定一个vector以及一个value,输出vector中所有小于该value的值,假设value为7。
解:这是一道再简单不过的题目,很随意地就写出了以下代码:
- 原始代码
std::vector<int> less_than(std::vector<int>&vec){
std::vector<int> rvec;
for(int i = 0 ; i < vec.size() ; i ++){
if(vec[i] < 7)
rvec.push_back(vec[i]);
}
return rvec;
}
- 函数模板
但这不是一个很好的解决办法,因为当我们想判断函数小于8时,需要建一个新的函数。而且,当我们要判断double或其他类型的数据时,需要对每个类型的数据都写个函数。很自然的我们想到将value用形参传入,且添加模板。于是将代码可以改成:
//模板
template<typename inputType>
std::vector<inputType> less_than(std::vector<inputType> &vec , inputType filterValue){
std::vector<inputType> rvec;
for (int i = 0 ; i < vec.size() ; i++){
if (pred(vec[i] , filterValue)){
rvec.push_back(vec[i]);
}
}
return rvec;
}
- 函数指针
我虽然用模板技术解决了对每个参数类型写相对应函数的问题,但是到目前为止我只是解决了 less_than这个问题,如果对equal或是greater等比较操作,我需要对这些操作写相应函数。但实际上,我发现这些函数的代码有很多相同的部分,完全可以融合到一个函数里。于是我想到了引入一个参数来表示需要进行的是哪一项操作,然后通过switch语句进行判断。但如果这么写,我又被操作项的个数所束缚,这不是一个一般性的解决方案。并且我如果添加switch语句的话,程序的显得很臃肿,程序结构显得模糊,当然这不是个良好的编程习惯。
//函数指针pred
//此时有两个方式来实现此操作:1沿袭之前通过vec.size()来判断是否达到了vector的下界;2定义一个pvec表示遍历vector时当前位置,此时pvec更像是数组中的index
//less_than 和 greater函数,有效地达到了隔离的效果。我原本想对这两个函数也用模板实现的,但如果我这样做在vs2012下会报错,不知道看到这的读者们有没有更好的抽象办法。
template<typename inputType>
std::vector<inputType> filter(std::vector<inputType> &vec ,
inputType filterValue , bool (*pred)(inputType , inputType)){
std::vector<inputType> rvec;
std::vector<inputType>::iterator pvec = vec.begin();
/*for (int i = 0 ; i < vec.size() ; i++){
if (pred(vec[i] , filterValue)){
rvec.push_back(vec[i]);
}
}*/
for( ; pvec < vec.end() ; pvec++){
if(pred(*pvec,filterValue)){
rvec.push_back(*pvec);
}
}
return rvec;
}
bool less_than(int v1 , int v2){
return v1 < v2 ? true : false;
}
bool greater(int v1 , int v2){
return v1 > v2 ? true : false;
}
- 更深的思考:function object
发现引入函数指针后,是程序结构变得清晰、降低了耦合度,但是我需要对每个操作额外写相应的代码,无疑增加了我的工作量。其实还有更加简便的办法来达到相同的目的,更详细的内容可参考标准库对于function object的描述。
//需要在开头添加#include<functional>
//利用adapter修改filter函数
template<typename inputType>
std::vector<inputType> advanceFilter(std::vector<inputType> &vec , inputType value , std::less<inputType> &lrh){
std::vector<inputType> pvec;
std::vector<inputType>::iterator iter = vec.begin();
//iter没遍历到最后时
//将value绑定到第二个操作数上去,lrh是less的对象
while ((iter = find_if(iter , vec.end() , std::bind2nd(lrh , value))) != vec.end()){
pvec.push_back(*iter);
iter ++;
}
return pvec;
}
- 泛型函数
写到这里,我已经做到了包括数据类型、比较关系在内的泛型,但是很无奈的一件事就是fileter或是advanceFilter函数都与vector容器存在着依赖关系,能不能更加抽象地解决这层依赖关系做到更加泛型化呢。我们需要对输入元素类型、判断数据类型、输出类型以及一个函数指针类型(或是function object对象类型)进行抽象,代码如下:
/*//
pram:
first:指向待查找部分的开头
last:指向待查找部分末尾的下一个
result:返回的结果
value:待比较的数据
pred:less、greater等比较关系
*/
template<typename inputIterator , typename outputInterator,
typename valueType , typename Com>
outputInterator filter(inputIterator first , inputIterator last ,
outputInterator result ,const valueType &value , Com pred){
while ((first = find_if(first , last , std::bind2nd(pred , value))) != last){
std::cout<<*first<<"\t";
*result ++ = *first ++;
}
std::cout<<std::endl;
return result;
}
写到这基本实现了一个简单的泛型算法