一、基本概念
就是使一个类的使用看上去像一个函数
。其实现就是类中实现一个operator()
,这个类就有了类似函数的行为,就是一个仿函数类;
class Func {
public:
void operator() () const {
statements;
}
};
1.1 为什么有仿函数,这样做有什么好处呢?
STL中也大量涉及到仿函数,有时仿函数的使用是为了函数
拥有类的性质,以达到安全传递函数指针
、依据函数生成对象
、甚至是让函数之间有继承
关系、对函数进行运算
和操作
的效果;
//less的定义
template<typename _Tp>
struct less : public binary_function<_Tp, _Tp, bool>
{
bool operator()(const _Tp& __x, const _Tp& __y) const
{ return __x < __y; }
};
//set的申明
template<typename _Key,
typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<_Key>>
class set;
- 比一般函数
灵巧
,可拥有状态
;对于仿函数,可同时拥有两个状态不同的实体;
- 每个仿函数都有其
型别
,可使用template来传参
;
- 阔以使用
内联函数
,执行速度通常比函数指针更快
;
- 阔以使用
成员变量
,以免去对一些公共变量
的维护,也可以使重复使用的代码独立出来;
- 也阔以进行
依赖
、组合
与继承
;
1.2 仿函数可作为什么?
在开发过程经常需要使用已序
的对象置于容器中,但我们一般不使用operator
来排序,从而使用仿函数来操作;
class FuncSort {
public:
/** 可自定义排序准则 */
void operator() (const Person& p2) const {
return num < p2.num;
}
};
1.3 仿函数的内部状态?
/*----------------------------------------------------------------------
> File Name: test.cpp
> Author: Jxiepc
> Mail: Jxiepc
> Created Time: Mon 07 Mar 2022 04:08:01 PM CST
----------------------------------------------------------------------*/
#include <iostream>
#include <algorithm>
#include <list>
class Func {
public:
Func(int val) : m_val(val) {
}
int operator() () {
return m_val++;
}
private:
int m_val;
};
int main(int argc, char* argv[])
{
std::list<int> coll;
std::generate_n(std::back_inserter(coll),
9,
Func(4));
for(auto& i:coll) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
根据以上实例,仿函数可维持内部val
的数值,进而叠加
;
1.3.1 pass by value
当使用传值
时,算法不会改变随参数而来的仿函数状态,若改变只是其中的副本
;
int main(int argc, char* argv[])
{
std::list<int> coll;
Func f(1);
std::generate_n(std::back_inserter(coll),
9,
f);
std::generate_n(std::back_inserter(coll),
9,
f);
for(auto& i:coll) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
1.3.3 pass by reference
当使用引用传参(或使用for_each)时,即可从中获取结果
或反馈
;
int main(int argc, char* argv[])
{
std::list<int> coll;
Func f(1);
std::generate_n<std::back_insert_iterator<std::list<int> >, int, Func&> (std::back_inserter(coll), 9, f);
std::generate_n(std::back_inserter(coll),
9,
f);
for(auto& i:coll) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
1.3.4 for_each的回返值
出现了该函数可代替引用传参
的方式,来获取存储的最终状态
;
// 返回值为仿函数类型,在仿函数内部提供一个状态返回即可通过该返回值进行查询;
template<typename InputIterator, typename Function>
Function for_each(InputIterator beg, InputIterator end, Function f) {
while(beg != end)
f(*beg++);
}
三、判断式与仿函数
3.1 基本概念
即返回布尔值
的一个函数或者仿函数;
3.2 判断式不应该被调用而改变自身的状态
为了保证这一点需要将operator声明为const成员函数
;
四、STL中标准仿函数
其中通过操作数进行划分为一元和二元,通过功能划分为算术、关系、逻辑运算;
4.1 满足STL的仿函数需要有哪些要求呢
必须定义相应的型别,为了让配置器能够萃取出类型;
该型别通过typedef设定,该操作于编译器即完成,不会影响效率及带来负担;
需要的型别有哪些呢?STL提供了unary_function和binary_function分别为一元二元的型别;
unarg_function
template<class Arg, class Result>
struct unary_function {
typedef Arg argument_type;
typedef Result result_type;
};
binary_function
template<class Arg1, class Arg2, class Result>
struct binary_function {
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
这些型别在我们真正使用仿函数时一般用不到,那用在何处呢???
一般用在适配器上;
template<class Operation>
class binder1st {
protected:
Operation op;
typename Operation::first_argument_type value;
public:
typename Operation::result_type operator()(const typename Opreator::second_argument_type& x) const {
// ....
}
};
4.2 STL中的identity、select、project仿函数
此类函数为STL了提供了间接性;
【identity】:证同函数,数值通过该函数,不会有任何变化;使用在map、set中告诉该类key如何得到;
【select】:选择函数,接收pair返回第一个或第二个参数;
【project】:投射函数,传回第一个或第二参数;
identity
template<class T>
struct identity : public unary_function<T, T> {
const T& operator()(const T& x) const { return x; }
};
select
template<class Pair>
struct select1st : public unary_function<Pair, typename Pair::first_type>{
const typename Pair::first_type& operator()(const Pair& x) const {
return x.first;
}
};
template<class Pair>
struct select2nd : public unary_function<Pair, typename Pair::second_type>{
const typename Pair::second_type& operator()(const Pair& x) const {
return x.seond;
}
};
project
template<class Args1, class Args2>
struct project1st : public binary_function<Args1, Args2, Args1> {
Args1 operator()(const Args1& x, const Args2&) const { return x;}
};
template<class Args1, class Args2>
struct project2nd : public binary_function<Args1, Args2, Args2> {
Args2 operator()(const Args1&, const Args2& y) const { return y;}
};
4.3 常用仿函数
头文件为:functional
;
仿函数 |
作用 |
negate<>() |
- p |
plus<>() |
p1 + p2 |
minus<>() |
p1 - p2 |
multiplies<>() |
p1 * p2 |
divides<>() |
p1 / p2 |
modulus<>() |
p1 % p2 |
equal_to<>() |
p1 == p2 |
no_equal_to<>() |
p1 != p2 |
less<>() |
p1 < p2 |
greater<>() |
p1 > p2 |
less_equal<>() |
p1 <= p2 |
greater_equal<>() |
p1>=p2 |
logical_not<>() |
!p |
logical_and<>() |
p1 && p2 |
logical_or<>() |
p1 || p2 |