自定义泛型函数、以函数作为算法参数、仿函数等内容总结

本文总结了C++中自定义泛型函数的实现,通过全局内联模板函数展示了如何创建适用于不同容器的STL算法。讨论了typename在模板中的作用,解释了在模板解析时解决嵌套依赖类型名的规则。此外,探讨了以函数作为算法参数的用法,以for_each和transform为例,并讲解了一元和二元判断式。仿函数的概念也被介绍,包括如何通过重载操作符实现。最后,举例说明了STL预定义仿函数如less、greater等的应用。
摘要由CSDN通过智能技术生成

自定义泛型函数的程序代码及实验结果如下:

#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个容器迭代器参数。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值