初学STL子仿函数和函数适配器之一

5 篇文章 0 订阅
仿函数即定义了operator()的对象。

如:FuncitonObjectTypeClass fo;

fo(...);

其中fo()是调用fo的operator(),而非调用fo().这一点很重要是核心。

也就是说并不是将所有语句放在一般的函数中。

 void fo(){ statements}

而是放在operator()中如下:

class FuncitonObjectTypeClass
{
     public:
            void operator()()
            {
                    statements;
            }
}

这个特性常用在有序的容器中。如以下。

对一个拥有Person对象的容器,按照Person的名称进行排序,要是名称相同按照年龄排序。

则可以这样使用。

//二段判式
class Person
{
public:
	string name;
	int age;
};

class PersonSortCriterion
{
public :
	bool operator() (const Person& p1,const Person& p2) const 
	{
		return p1.name < p2.name || 
			((p1.name == p2.name) && p1.age < p2.age);
	}
};

测试代码如下:

Person per1;
	per1.name = "aaaa";
	per1.age = 23;
	
	Person per2;
	per2.name = "aaab";
	per2.age = 24;

	Person per3;
	per3.name = "aaaa";
	per3.age = 21;	

	Person per4;
	per4.name = "bbbb";
	per4.age = 21;

	cout<<"----Person仿函数排序----start--"<<endl;
	typedef set<Person,PersonSortCriterion> PersonSet;
	PersonSet personSotFunction;

	personSotFunction.insert(per1);
	personSotFunction.insert(per2);
	personSotFunction.insert(per3);
	personSotFunction.insert(per4);

	PersonSet::iterator posPersonSet;
	for (posPersonSet = personSotFunction.begin();posPersonSet != personSotFunction.end();++posPersonSet)
	{
		cout<<"personName: "<<(*posPersonSet).name<<"   personAge: "<<(*posPersonSet).age<<endl;
	}
	cout<<"----Person仿函数排序----end--"<<endl;

 

 

 

 

 

 

  

 

第二:拥有内部状态的仿函数。注意仿函数都是按值传递,并不是按址传递。所以调用后并不会改变仿函数的内部状态。示例代码如下。

实例1:产生一个初始值的序列。每次调用都为序列加1

//仿函数如下:

//以初始化数累加的序列
class IntSequence
{
private:
	int value;
public:
	IntSequence(int initialValue):value(initialValue)
	{
	}
	int operator()()
	{
		return value++;
	}
};

//测试代码如下,其中PRINT_ELEMENTS是用于打印容器元素的。

cout<<"-------functors------------"<<endl;
	list<int> listFuctor;
	IntSequence seq(1);
	generate_n(back_inserter(listFuctor),4,seq);
	PRINT_ELEMENTS(listFuctor,"Value: ");
	generate_n(back_inserter(listFuctor),4,IntSequence(42));

	PRINT_ELEMENTS(listFuctor,"insertValue: ");

	generate_n(back_inserter(listFuctor),4,seq);

	PRINT_ELEMENTS(listFuctor,"RepeatSeq: ");


//PRINT_ELEMENTS,是个模板方法,方法如下

template<class T>
inline void PRINT_ELEMENTS(const T& coll, const char* optcstr)
{
	typename T::const_iterator pos;
	std::cout << optcstr;
	for(pos = coll.begin();pos != coll.end();++pos)
	{
		std::cout<< *pos << ' ';
	}
	std::cout<<std::endl;
}

cout<<"-------functors------------"<<endl;
	list<int> listFuctor;
	IntSequence seq(1);
	generate_n<back_insert_iterator<list<int> >,int,IntSequence& >(back_inserter(listFuctor),4,seq);

	PRINT_ELEMENTS(listFuctor,"ByReference: ");

	generate_n(back_inserter(listFuctor),4,IntSequence(42));

	PRINT_ELEMENTS(listFuctor,"insertValue: ");

	generate_n(back_inserter(listFuctor),4,seq);

	PRINT_ELEMENTS(listFuctor,"RepeatSeq: ");

 由结果可以看出,IntSeque仿函数的内部状态并没有因为第一次的调用而被改变。所以要注意仿函数是按值来传递参数的。

实例二:for_each()的返回值。for_each的独特之处在于可以返回仿函数,这样就额可以通过for_each()的返回值来获取仿函数的状态。这里的状态其实也可以理仿函数中的某一个成员变量的返回值,或者某一个成员变量的值。

//定义仿函数

//求平均数的仿函数
class MeanValue
{
private:
	long num;
	long sum;
public:
	MeanValue():num(0),sum(0)
	{
	}
	void operator()(int elem)
	{
		num++;
		sum += elem;
	}
	double value()
	{
		return static_cast<double>(sum) / static_cast<double>(num);
	}
};


//调用的地方:

	cout<<"==========for_each返回值============"<<endl;

	list<int> collRepeatList;
	for (index = 1;index < 9;++index)
	{
		collRepeatList.push_back(index);
	}

	PRINT_ELEMENTS(collRepeatList,"collRepeat: ");

	MeanValue mv = for_each(collRepeatList.begin(),collRepeatList.end(),MeanValue());

	cout<<"MeanValue: "<<mv.value()<<endl;

注意其中的for_each的值。它返回仿函数后,就可以调用仿函数的value方法。这个用法相当的灵活。for_each的独门绝技啊。O(∩_∩)O~

结果如下:

 

 

仿函数就介绍这些基本的应用。下面介绍适配器的一些实用。由于篇幅太长。改在下一篇中介绍吧。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值