现在的位置: 首页 > 综合 > 正文

仿函数与函数配接器

2018年03月30日 ⁄ 综合 ⁄ 共 6355字 ⁄ 字号 评论关闭

转至:http://kymcuc.blog.163.com/blog/static/201942114201249105211285/

1、基本概念

所谓仿函数是一个定义了operator()的对象。虽然定义形式显然更为复杂,却有三大妙处
(1)仿函数比一般函数更灵巧。因为它可以拥有状态。事实上对于仿函数,可以同时拥有两个状态不同的实体
(2)每个仿函数都有其型别。因此可以将仿函数的型别当做template参数来传递。从而指定某种行为模式。此外还有一个好处:容器也会因为仿函数的不同而不同。
(3)执行速度上,仿函数通常比函数指针更快。
2.、仿函数可当做排序准则
要将某些类对象已已序形式置于容器中,则需要排序准则来排序,这个准则可以通过在类中重载operator<或定义一个函数来定义。
3、拥有内部状态的仿函数

#include<iostream>
#include<list>
#include<iterator>
#include<algorithm>
using namespace std;
class is{
private:
int value;
public:
is(int i):value(i){}
int operator()(){return value++;}
//仿函数的第二个括号里面是参数,实参是容器内的元素
};
int main()
{
list<int> coll;
is seq(1);
::generate_n<::back_insert_iterator<list<int>>,int,is&>//指定各个参数类型,其中第三个参数指定为引用,因而会保持状态的改变
(::back_inserter(coll),4,seq);
::generate_n(::back_inserter(coll),4,is(42));//表示将从42开始的4个值复制到coll中,这个默认是值传递
::generate_n(::back_inserter(coll),4,seq);//由于在第一次时,状态保存所以从五开始
for(list<int>::iterator i=coll.begin();i!=coll.end();++i)
cout<<*i<<" ";
cout<<endl;
}

4、for_each的返回值

其返回值是其仿函数,这样就可以通过for_each的返回值来获取仿函数的状态

#include<iostream>
#include<vector>
#include<algorithm>
#include<iterator>
#include<memory>
using namespace std;
class mean{
private:
long num;
long sum;
public:
mean():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<7;i++)
coll.push_back(i);
mean v=for_each(coll.begin(),coll.end(),mean());
cout<<v.value()<<endl;
}

由于内部实现等原因,不应该传递一个行为取决于被拷贝次数或被调用次数的仿函数。

5、预定义的仿函数
这些函数包含在头文件< functional >,这些函数包括基本算术运算和基本的逻辑运算
6、函数配接器
表达式 效果
bind1st(op,value) op(value,param)
bind2nd(op,value) op(param,value)
not1(op) !op(param)
not2(op) !op(param1,param2)

#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
int main()
{
vector<int> coll;
for(int i=1;i<=7;i++)
coll.push_back(i);
vector<int>::iterator iter;
iter=::find_if(coll.begin(),coll.end(),::not1(::bind2nd(::modulus<int>(),2)));
//对于所有奇数值,::bind2nd(::modulus<int>(),2)返回1,所以这个表达式用来找出第一个
//奇数值,对其取反表示找到第一个偶数值
cout<<*iter<<endl;
}

7、针对成员函数而设计的函数配接器
表达式 效果
mem_fun_ref(op) 调用op,那是某对象的一个const成员函数
mem_fun(op) 调用op,那是某对象指针的一个const成员函数

#include<iostream>
#include<functional>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
class p{
private:
string name;
public:
p(string n):name(n){}
void print()const{cout<<name.c_str()<<endl;}
void printw(string pre){cout<<pre.c_str()<<": "<<name.c_str()<<endl;}
};
int main()
{
vector<p> coll;//对象调用mem_fun_ref
vector<p*> coll1;//对象指针调用mem_fun
coll.push_back(p("keyaming"));
::for_each(coll.begin(),coll.end(),::mem_fun_ref(&p::print));
p men("sg");
p* pmem=&men;
coll1.push_back(pmem);
::for_each(coll1.begin(),coll1.end(),bind2nd(::mem_fun(&p::printw),"girl"));
}

8、针对一般函数(非成员函数)而设计的函数配接器
表达式 效果
ptr_fun(op) op(param)
  op(param1,param2)

#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
bool check(int elem)
{
return elem!=3;
}
int main()
{
vector<int> coll;
for(int i=0;i<7;++i)
coll.push_back(i);
vector<int>::iterator pos;
pos=::find_if(coll.begin(),coll.end(),not1(ptr_fun(check)));
cout<<*pos<<endl;
}

9、让自定义的仿函数也可以使用函数配接器
可以编写自己的仿函数,但如果希望它们能够和函数配接器搭配使用,就必须满足某些条件,必须提供一些型别成员来反映其参数和返回值的型别。标准库提供了一些结构,仿函数只有继承这些结构就可以满足可配接的条件

template<class arg,class result>
struct unary_funtion{
typedef arg argument_type;
typedef result result_type;
}
template<class arg1,class arg2,class result>
struct binary_function{
tyepdef arg1 first_argument_type;
typedef arg2,second_argument_type;
typedef result result_type;
}

#include<iostream>
#include<functional>
#include<algorithm>
#include<iterator>
#include<vector>
#include<cmath>
using namespace std;
template<class t1,class t2>
struct fopow:public std::binary_function<t1,t2,t1>
//继承之后即可使用配接器
{
t1 operator()(t1 base,t2 exp)const
{
return pow(base,exp);
}
};
int main()
{
vector<int> coll;
for(int i=0;i<7;++i)
coll.push_back(i);
::transform(coll.begin(),coll.end(),::ostream_iterator<int>(cout," "),::bind2nd(fopow<float,int>(),2));
cout<<endl;
}

10、辅助用仿函数
功能 采用名称
f(g(elem)) compose_f_gx
f(g(elem1,elem2))  
f(g(elem),h(elem)) compose_f_gx_hx
f(g(elem1),h(elem2)) compose_f_gx_hy

compose.h
#pragma
#include<functional>
namespace compose{
template<class OP1,class OP2>
class compose_f_gx_t:public std::unary_function<typename OP2::argument_type,typename OP1::result_type>
{
private:
OP1 op1;
OP2 op2;
public:
compose_f_gx_t(const OP1&o1,const OP2&o2):op1(o1),op2(o2){}
typename OP1::result_type operator()(const typename OP2::argument_type&x)const{
return op1(op2(x));
}
};
template<class OP1,class OP2>
inline compose_f_gx_t<OP1,OP2>
compose_f_gx(const OP1&o1,const OP2&o2){
return compose_f_gx_t<OP1,OP2>(o1,o2);
}
}
namespace compose{
template<class OP1,class OP2,class OP3>
class compose_f_gx_hx_t:public std::unary_function<typename OP2::argument_type,typename OP1::result_type>
{
private:
OP1 op1;
OP2 op2;
OP3 op3;
public:
compose_f_gx_hx_t(const OP1&o1,const OP2&o2,const OP3&o3):op1(o1),op2(o2),op3(o3){}
typename OP1::result_type operator()(const typename OP2::argument_type&x)const{
return op1(op2(x),op3(x));
}
};
template<class OP1,class OP2,class OP3>
inline compose_f_gx_hx_t<OP1,OP2,OP3>
compose_f_gx_hx(const OP1&o1,const OP2&o2,const OP3&o3){
return compose_f_gx_hx_t<OP1,OP2,OP3>(o1,o2,o3);
}
}
namespace compose{
template<class OP1,class OP2,class OP3>
class compose_f_gx_hy_t:public std::binary_function<typename OP2::argument_type,typename OP3::argument_type,typename OP1::result_type>
{
private:
OP1 op1;
OP2 op2;
OP3 op3;
public:
compose_f_gx_hy_t(const OP1&o1,const OP2&o2,const OP3&o3):op1(o1),op2(o2),op3(o3){}
typename OP1::result_type operator()(const typename OP2::argument_type&x,const typename OP3::argument_type&y)const{
return op1(op2(x),op3(y));
}
};
template<class OP1,class OP2,class OP3>
inline compose_f_gx_hy_t<OP1,OP2,OP3>
compose_f_gx_hy(const OP1&o1,const OP2&o2,const OP3&o3){
return compose_f_gx_hy_t<OP1,OP2,OP3>(o1,o2,o3);
}
}

#include"compose.h"
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
#include<string>
#include<cctype>
using namespace std;
int main()
{
vector<int> coll;
for(int i=0;i<7;++i)
coll.push_back(i);
::transform(coll.begin(),coll.end(),
::ostream_iterator<int>(cout," "),
compose::compose_f_gx(::bind2nd(::multiplies<int>(),5),::bind2nd(::plus<int>(),10)));
vector<int>::iterator iter;
iter=::remove_if(coll.begin(),coll.end(),
compose::compose_f_gx_hx(
::logical_and<bool>(),
::bind2nd(::greater<int>(),2),
::bind2nd(::less<int>(),5))
);
::copy(coll.begin(),iter,::ostream_iterator<int>(cout," "));
cout<<endl;
string s("helloworld");
string sub("llowo");
string::iterator iter1;
iter1=::search(s.begin(),s.end(),
sub.begin(),sub.end(),
compose::compose_f_gx_hy(::equal_to<int>(),
::ptr_fun(::toupper),
::ptr_fun(::toupper)));
}

抱歉!评论已关闭.