仿函数

仿函数三大妙处:

1、仿函数比一般函数更灵巧,因为它可以拥有状态。事实上对于仿函数,你可以同时拥有两个状态不同的实体。

2、每个仿函数都有其型别。因为你可以将仿函数的型别当作template参数来传递,从而指定某种行为模式,容器型别也会因为仿函数的不同而不同。

3、执行速度上,仿函数通常比函数指针更快。就template概念而言,很多细节在编译期就已确定。

仿函数是以by value方式传递的好处是,你可以传递常量或暂时表达式,如果不这样设计,就不能传递ClassName(1)这样的表达式(临时对象),至于缺点是无法改变仿函数的状态。因为你改变的只是副本而已。然而我们有时候确实需要存取最终状态。因此,问题在于如何从一个算法中获取结果。

有两个办法可以从“运用了仿函数”的算法中获取“结果”或“反馈”。

1、以by reference的方式传递仿函数(仅限参考,不一定管用)

2、运用for_each()算法的回返值

例1:by reference(在vs2013上不管用,原因如注释)

#include <iostream>
#include <list>
#include<algorithm>
#include<iterator>

using namespace std;


class IntSequence{
private:
	int value;
public:
	IntSequence(int initialValue) :value(initialValue){};

	int operator()()
	{
		return value++;
	}
};

int main()
{
	list<int> coll;
	IntSequence seq(1);

	generate_n<back_insert_iterator<list<int>>, int, IntSequence&>(back_inserter(coll), 4, seq);//在该算法内部,调用了另外的模板                                                                                                   //进行了传值,而不是by reference
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	generate_n(back_inserter(coll), 4, IntSequence(42));
	generate_n(back_inserter(coll), 4, seq);
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	system("pause");
	return 0;
}

例2:for_each()

#include <iostream>
#include <vector>
#include<algorithm>
#include<iterator>

using namespace std;


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);
	}
};

int main()
{
	vector<int> coll;
	for (int i = 1; i <= 8; ++i)
	{
		coll.push_back(i);
	}
	MeanValue mv = for_each(coll.begin(), coll.end(), MeanValue());
	cout <<"mean value"<<mv.value()<< endl;

	system("pause");
	return 0;
}

输出:mean value4.5

一个陷阱:

#include <iostream>
#include <list>
#include<algorithm>
#include<iterator>

using namespace std;

class Nth{
private:
	int nth;
	int count;
public:
	Nth(int n) :nth(n), count(0){}

	bool operator()(int){
		return ++count == nth;
	}
};


int main()
{
	list<int> coll;
	for (int i = 1; i <= 9; ++i)
	{
		coll.push_back(i);
	}
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;
	list<int>::iterator pos;
	pos = remove_if(coll.begin(), coll.end(), Nth(3));
	coll.erase(pos, coll.end());
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;
	system("pause");
	return 0;
}

输出:

1 2 3 4 5 6 7 8 9
1 2 4 5 7 8 9   //3和6都被删除了

下面是remove_if的一般实作:

template<class ForwIter,class Predicate>
ForwIter std::remove_if(ForwIter beg, ForwIter end, Predicate op)
{
 beg = find_if(beg, end, op);
 if (beg == end)
 {
  return beg;
 }
 else
 {
  ForwIter next = beg;
  return remove_copy_if(++next, end, beg, op);
 }
}

find_if传值,remove_copy_if中op的count从零开始,即在实施删除时又进行了一次删除。

解决方法:总是将判断式operator()声明为const成员函数。

预定义的仿函数:

#include<functional>

仿函数

效果

negate<type>()

-param

plus<type>()

param1+param2

minus<type>()

param1-param2

multiplies<type>()

param1*param2

divides<type>()

param1/param2

modulus<type>()

param1%param2

equal_to<type>()

param1==param2

not_equal_to<type>()

param!=param2

less<type>()

param1<param2

greater<type>()

param1>param2

less_equal<type>()

param1<=param2

greater_equal<type>()

param1>=param2

logical_not<type>()

!param

logical_and<type>()

param1&&param2

logical_or<type>()

param1||param2

函数配接器:

表达式

效果

bind1st(op,value)

op(value,param)

bind2nd(op,value)

op(param,value)

not1

!op(param)

not2

!op(param1,param2)

针对成员函数而设计的函数配接器

mem_fun_ref(op)

调用op,那是某对象的一个const成员函数

mem_fun(op)

调用op,那是某对象指针的一个const成员函数

针对一般函数而设计的函数配接器

ptr_fun(op)

op(param)

op(param1,param2)

例子:mem_fun_ref

vs2013不要求成员函数为const

</pre><pre class="cpp" name="code">class Person{
private:
	string name;
public:
	Person(string na) :name(na){}
	void print() const{
		cout << name << endl;
	}
	void printWithPrefix(string prefix)const
	{
		cout << prefix << name << endl;
	}
};
list<Person> coll;
for_each(coll.begin(), coll.end(), mem_fun_ref(&Person::print));
for_each(coll.begin(), coll.end(), bind2nd(mem_fun_ref(&Person::printWithPrefix), "person:"));
list<Person*> coll;
for_each(coll.begin(), coll.end(), mem_fun(&Person::print));
for_each(coll.begin(), coll.end(), bind2nd(mem_fun(&Person::printWithPrefix), "person:"));

mem_fun_ref和mem_fun两者都能以无参数或单参数方式来调用成员函数。
ptr_fun:

假设有一个能对每个参数实施某种检测的全局函数如下:

bool check(int elem)

如果要搜寻第一个令检查失败的元素,可以如下:

pos=find_if(coll.begin(),coll.end(),not1(ptr_fun(check)));

这里ptr_fun不可省略,因为not1()需要用到仿函数提供的某些特殊型别。

第二种用法,你有一个双参数全局函数,又想把它当成一个单参数函数使用

pos=find_if(coll.begin(),coll.end(),bind2nd(ptr_fun(strcmp),""));

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值