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

Posted 张三和李四的家

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++标准库 STL —— 仿函数和适配器相关的知识,希望对你有一定的参考价值。

仿函数

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';

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

绑定数据成员

struct Foo

    int a, b;
;

Foo pair1,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 是一个类吗?不,它是一个对象。因为你不能直接拿一个类来使用。

以上是关于C++标准库 STL —— 仿函数和适配器的主要内容,如果未能解决你的问题,请参考以下文章

C++ STL 基础及应用 函数对象(仿函数)

STL 简介

STL标准库-容器适配器

STL标准库-迭代器

STL源码剖析

C++标准库