自定义泛型函数的程序代码及实验结果如下:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;<pre name="code" class="cpp">//PRINT_ELEMENT泛型函数原型开始
template<class T>
inline void PRINT_ELEMENT(const T& t,const char* title=""){
cout<<title<<endl;
typename T::const_iterator it;
for(it=t.begin();it!=t.end();it++){
cout<<*it<<endl;
}
}<pre name="code" class="cpp">//PRINT_ELEMENT泛型函数原型结束
int main(){
vector<string> coll;
coll.push_back("nihao");
coll.push_back("hello");
coll.push_back("how are you");
coll.push_back("lelele");
PRINT_ELEMENT(coll,"test case 1:");
return 0;
}
从上例可以看出,我采用了全局内联函数来实现PRINT_ELEMENT这一自定义STL算法,而且这是一个模板函数,针对不同容器都能适用,typename的使用在此用于标识nested dependent name(嵌套依赖类型名),这与之前typename作为关键字与template搭配使用于声明模板类型(如template<typename T>,此处typename等同于class)不同。直到 T 成为已知之前,没有任何办法知道T::const_iterator 到底是不是一个 type(类型),而当 template(模板)PRINT_ELEMENT被解析的时候,T还不是已知的。C++ 有一条规则解决这个歧义:如果解析器在一个 template(模板)中遇到一个 nested dependent name(嵌套依赖名字),它假定那个名字不是一个 type(类型),除非你用其它方式告诉它。缺省情况下,nested dependent name(嵌套依赖名字)不是 types(类型),所以需要使用typename关键字告诉编译器它是一个嵌套依赖类型。
以函数作为算法的参数,比如for_each、transform等,一下为测试实例:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>
using namespace std;
template<class T>
inline void PRINT_ELEMENT(const T& t,const char* title=""){
cout<<title<<endl;
typename T::const_iterator it;
for(it=t.begin();it!=t.end();it++){
cout<<*it<<endl;
}
}
void print(pair<string,int> a){
cout<<a.first<<" "<<a.second<<endl;
}
string doublechange(string a){
a+=a;
return a;
}
int main(){
vector<string> coll;
coll.push_back("nihao");
coll.push_back("hello");
coll.push_back("how are you");
coll.push_back("lelele");
PRINT_ELEMENT(coll,"initial:");
map<string,int> cont;
cont["hello"]=111;
cont["nihao"]=222;
cont["lelele"]=333;
for_each(cont.begin(),cont.end(),print);
vector<string> doll(3,"next");
transform(coll.begin(),coll.end(),back_inserter(doll),doublechange);//inserter(doll,doll.begin()) //back_inserter(doll)
PRINT_ELEMENT(doll,"doublechanged: ");
return 0;
}
对for_each函数而言,其参数函数的输入变量为容器的每个元素,比如map容器使用for_each算法,传入类型就是pair对组变量;transform的使用第三个参数尤其麻烦,因为需要使用插入型迭代器即back_inserter、front_inserter、inserter等,也是元素传入,返回新的元素,并插入到新容器里面。
算法中有一种函数叫做判断式,分为一元判断式和二元判断式,分别以find_if和sort举例说明如下:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>
using namespace std;
bool isPrime(int x){
<span style="white-space:pre"> </span>x=abs(x);
<span style="white-space:pre"> </span>if(x==0||x==1)
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>for(int i=2;i<=sqrt(x);i++){
<span style="white-space:pre"> </span>if(x%i==0)
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return true;
}
bool comp(int x,int y){
<span style="white-space:pre"> </span>if(x<y)
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>return true;
}
int main(){<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>vector<int> a;
<span style="white-space:pre"> </span>for(int i=0;i<10;i++){
<span style="white-space:pre"> </span>a.push_back(i);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>copy(a.begin(),a.end(),ostream_iterator<int>(cout," "));
<span style="white-space:pre"> </span>cout<<endl;
<span style="white-space:pre"> </span>vector<int>::iterator it=a.begin();
<span style="white-space:pre"> </span>while(it!=a.end()){
<span style="white-space:pre"> </span>it=find_if(it,a.end(),isPrime);
<span style="white-space:pre"> </span>if(it!=a.end())
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>cout<<*it<<endl;
<span style="white-space:pre"> </span>it++;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>sort(a.begin(),a.end(),comp);
<span style="white-space:pre"> </span>copy(a.begin(),a.end(),ostream_iterator<int>(cout," "));
<span style="white-space:pre"> </span>return 0;<span style="white-space:pre"> </span>
}
以上为一个判断数组元素是否为质数的例子,find_if函数的第三个参数为一个判断式,返回布尔变量,sort函数有两种调用形式,两参数的sort默认为由小到大的排序,三参数的sort需要自己设计比较函数,本文定义为由大到小的顺序,其中comp为二元判断式,两个元素分别表示前者和后者。
仿函数由于其调用类似于函数调用而得名,其实就是括号运算符的重载,以下为实例:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>
using namespace std;
void addnum(int& element){
element-=5;
}
int addstable(int element){
return element+5;
}
template<int theValue>
int addknown(int element){
return element+theValue;
}
class addunknown{
private:
int theValue;
public:
addunknown(int x):theValue(x){
}
int operator()(int element){
return element+theValue;
}
};
int main(){
vector<int> a;
for(int i=0;i<10;i++){
a.push_back(i);
}
copy(a.begin(),a.end(),ostream_iterator<int>(cout," "));
cout<<endl;
for_each(a.begin(),a.end(),addnum);
copy(a.begin(),a.end(),ostream_iterator<int>(cout," "));
cout<<endl;
vector<int> b;
transform(a.begin(),a.end(),back_inserter(b),addstable);
copy(b.begin(),b.end(),ostream_iterator<int>(cout," "));
cout<<endl;
vector<int> c;
transform(a.begin(),a.end(),back_inserter(c),addknown<10>);
copy(c.begin(),c.end(),ostream_iterator<int>(cout," "));
cout<<endl;
vector<int> d;
int x;
cin>>x;
transform(a.begin(),a.end(),back_inserter(d),addunknown(x));
copy(d.begin(),d.end(),ostream_iterator<int>(cout," "));
cout<<endl;
return 0;
}
上面分三种情况对数组a进行了改变,第一种是增加固定值的改变,只需在辅助函数里边直接增加就ok,第二种是增加已知数值的情况,我们定义一个模板函数addknown<5>通过模板工具传递增加的数值,第三种情况是增加变量的情况,此时我们采用仿函数的方法,定义一个类并添加构造函数和重载的括号函数,从而实现增加变量的作用,具体分析transform(a.begin(),a.end(),back_inserter(d),addunknown(x));该语句的第三个参数是一个仿函数形式,在编译器解析的时候回变为addunknown(x)();即首先调用类构造函数,然后调用重载的括号操作符。此外,说明一下,使用for_each改变容器内元素数值时,需要传递引用,如int& element。
STL中预先定义了一些仿函数,如less、greater、negate、multiplies等,使用实例如下所示:
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
set<int,greater<int>> a;
for(int i=0;i<10;i++){
a.insert(i);
}
copy(a.begin(),a.end(),ostream_iterator<int>(cout," "));
cout<<endl;
set<int,less<int>> b;
for(int i=0;i<10;i++){
b.insert(i);
}
copy(b.begin(),b.end(),ostream_iterator<int>(cout," "));
cout<<endl;
set<int> c;
transform(b.begin(),b.end(),inserter(c,c.begin()),negate<int>());
copy(c.begin(),c.end(),ostream_iterator<int>(cout," "));
cout<<endl;
set<int> d;
transform(b.begin(),b.end(),c.begin(),inserter(d,d.begin()),multiplies<int>());
copy(d.begin(),d.end(),ostream_iterator<int>(cout," "));
cout<<endl;
return 0;
}
可以看出set默认采用由小到大排序,transform的目标位置需要使用安插型迭代器,若目标容器的空间不够不使用安插型迭代器就会出现编译错误,multiplies实现两个容器相乘,需要3个容器迭代器参数。