C++【STL】 | 仿函数的应用以及如何规范要求

21 篇文章 1 订阅

一、基本概念

就是使一个类的使用看上去像一个函数。其实现就是类中实现一个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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jxiepc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值