仿函数三大妙处:
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&¶m2 |
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),""));