C++标准库 STL —— 仿函数和适配器

11 篇文章 0 订阅
2 篇文章 0 订阅

仿函数

function call operator 仿函数中的 函数名,是一个 operator()

仿函数主要是用来服务算法的,如果要被算法调用就需要重载 ()。这里称这种()function call operator

仿函数主要分为三大类:

  1. 算术类

    template <class T>
    struct plus : public binary_function<T, T, T> {
    	T operator()(const T& x, const T & y) const 
        { return x + y;}
    };
    
  2. 逻辑运算类

    template <class T>
    struct logical_and: public binary_function<T, T, bool>
    	bool operator()(const T& x, const T& y) const 
        {return x && y;}
    
  3. 相对关系类

    template <class T>
        struct equal_to : public binary_function<T, T, bool>
            bool operator()(const T& x, const T& y) const
        {return x == y;}
    

算法使用仿函数的场景

template<typename Iterator, typename Cmp>
Algorithm(Iterator itr1, Iterator itr2, Cmp Comp)
{}//cmp 即仿函数

为什么需要继承 binary_function?

template <class Arg1, class Arg2, class Reuslt>
    struct binary_function{
        typedef Arg1 first_argument_type;
        typedef Arg2 second_argument_type;
        typedef Result result_type;
    };

通过继承 binay_function ,仿函数获取到了一些typedef,而这些typedef 会被适配器所需要。

Adapter

容器适配器:用于改造容器

​ stack,queue 都内含了一个 deque,stack,queue 的功能都是由 deque 实现的,所有stack,queue 是 deque 的容器适配器。

仿函数适配器:用于改造仿函数

仿函数的可适配条件

STL 提供每个 Adaptable Function 都应挑选适当者继承(因为Function Adapter 将会提问)。例如:

templdate<class Arg1, classs Arg2, class Result>
    struct binary_function{
        typedef Arg1 Frist_argument_type;
        typedef Arg2 second_argument_type;
        typedef Result result_type;
    };
templdate <class T>
    struct less : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const {
            return x  < y;
        }
    };

上面是仿函数以及基类定义。

这些在 仿函数适配器中会被用到。

bind2nd(less<int>(), 40);//typename+() == 产生一个临时对象,less<int>()就是一个仿函数对象
template <class T> less<int T>{} //本来是用来比大小(x < y)的,被bing2nd 修饰了之后,函数功能发生了变化。
//现在函数的功能为 (x  < 40)

怎么实现的呢?

template <class _Operation, class _Tp>
inline binder2nd<_Operation> //返回的是什么
bind2nd(const _Operation& __oper, const _Tp& __x) 
{
  typedef typename _Operation::second_argument_type _Arg2_type;//关于这里的typename的作用
    /*
    	编译器在编译到 _Operator 时,但它还没有被使用,不知道是什么?只有在传入参数的时候才知道。所以编译器就犹豫这行代码是否会被编译通过。而typename 就告诉编译器,typename 后面的 是一个类型。需要被编译通过。
    */
  return binder2nd<_Operation>(__oper, _Arg2_type(__x));
}

template <class _Operation> 
class binder2nd
  : public unary_function<typename _Operation::first_argument_type,
                          typename _Operation::result_type> {
protected:
  _Operation op;//记下函数
  typename _Operation::second_argument_type value;//记下第二参数  需要是 _Operation::second_argument_type 类型
public:
  binder2nd(const _Operation& __x,
            const typename _Operation::second_argument_type& __y) 
      : op(__x), value(__y) {}
	
  // _Operation::result_type 按照原函数中的返回类型,进行返回
  typename _Operation::result_type
  operator()(const typename _Operation::first_argument_type& __x) const {
    return op(__x, value); //调用函数并返回
  }
};
typename
  • 在模板声明的模板参数列表中,可以使用typename代替类 来声明类型模板参数
  • 在模板的声明和定义中 typename 可用于声明从属限定名称为一个类型(防止编译器报错或警告)。

例如上面的typedef typename _Operation::second_argument_type _Arg2_type;

新型适配器

std::bind 绑定函数,可以绑定下面 object

  1. functions
  2. function objects
  3. member functions, _1 必须是某个 object 地址
  4. data members, _1 必须是某个object 地址

这个函数呢,会返回一个 function object ret。调用ret 相当于调用上述1, 2, 3, 或相当于取出4

绑定函数

auto fn_five = bind(my_divide, 10,2);
cout << fn_five() << '\n';

image-20210316143116519

上面截图显示了,bind 函数的函数签名。

绑定数据成员

struct Foo
{
    int a, b;
};

Foo pair{1,2};
auto memdata = bind(&Foo::a, pair);
cout << memdata() << endl;

下面展示和算法和混用

vector<int> v {51,52,40,20,70,20,59};

auto fn = bind(less<int>(), _1, 50);
cout << count_if(v.cbegin(), v.cend(), fn) << endl;
cout << count_if(v.begin(), v.end(), bind(less<int>(), _1, 50)) << endl;
cout << count_if(v.cbegin(), v.cend(), bind2nd(less<int>(), 50)) << endl;

迭代器适配器:用于改造迭代器

tuple

template <typename... Values> class tuple;
template<> class tuple<>{};

template <typename Head, typename... Tail>
class tuple<Head, Tail...>
        :private tuple<Tail...>
{
    typedef tuple<Tail...> inherited;
public:
    tuple(){}
    tuple(Head v, Tail... vtail)
        : m_head(v), inherited(vtail...){}

    typename Head::type head() { return m_head;}
    inherited& tail() { return *this;}//return  后,转型为 inherited ,实际获得的是 Tail...

protected:
    Head m_head;
};

tuple 一种类似于 pair 的集合型容器类。可以将不同类似的对象包装到一起。应该是可以包含无限的对象。

实现方式:通过递归继承来实现。

Traits

traits 获取对象的类型。

实现格式: 模板的泛化和特化



template <typename _Tp>
struct remove_const {
    typedef _Tp type;
};

template <typename _Tp>
struct remove_const<const _Tp> {
    typedef _Tp type;
};

template <typename _Tp>
struct remove_volatile {
    typedef _Tp type;
};

template <typename _Tp>
struct remove_volatile<volatile _Tp> {
    typedef _Tp type;
};

/*
 * 将传入的`const  volatile Type` 去掉 const 和 volatile ,还原原始的类型
 */
template <typename _Tp>
struct remove_cv{
    typedef typename remove_const<typename remove_volatile<_Tp>::type>::type type;
};

template<typename>
struct __is_void_helper
        :public false_type{};

template<typename>
struct __is_void_helper<void>:
        public true_type{};

template <typename _Tp>
struct is_void :
        public __is_void_helper<typename remove_cv<_Tp>::type>::type {};

cout

cout 是一个类吗?不,它是一个对象。因为你不能直接拿一个类来使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值