STL源码分析--functional

简介: STL源码分析--functional
  • 1 相关头文件


  • 2 一元函数对象


  • 2.1 binder1st/binder2nd


  • 2.2 unary_compose


  • 2.3 pointer_to_unary_function


  • 2.4 mem_fun_t


  • 2.5 其他


  • 3 二元函数对象


  • 3.1 mem_fun1_t


  • 3.2 其他



1 相关头文件


functional
functional.h
stl_function.h



2 一元函数对象


一元函数对象,是指这类函数对象只接受一个参数并返回一个参数。


unary_function为STL中所有一元函数对象的基类。它定义了一元函数对象的输入/输出参数类型,其中argument_type为输入参数类型,result_type为输出参数类型,这两种类型由输入模板参数推导而来。


template <class _Arg, class _Result>
struct unary_function {
  typedef _Arg argument_type;
  typedef _Result result_type;
};


下面介绍几种有意思的一元函数对象。



2.1 binder1st/binder2nd


binder1st的功能:将某个参数值绑定到可调用对象(Callable type,函数对象/函数指针/std::function)的第一个参数中。同理,binder2nd将某个参数值绑定到可调用对象的第二个参数中。


有了binder1st/binder2nd,便可利用已有的可调用对象生成各种变体,避免了重新定义带来的代码冗余。


auto f = [](double a, double b){ return 2*(a+b); };
    double a0 = 1.0;
    double b0 = 2.0;
    auto uf1 = std::binder1st(f, a0);
    auto uf2 = std::binder2nd(f, b0);
    std::cout << uf1(3.0) << std::endl; // 执行f函数,参数1:被绑定的a0, 参数2:3.0
    std::cout << uf2(4.0) << std::endl; // 执行f函数,参数1: 4.0,      参数2:被绑定的b0



binder1st内部嵌套了一个可调用对象op。生成binder1st对象时,其内部记录传入的可调用对象和绑定参数。当执行operator()时,其调用可调用对象并返回结果。


template <class _Operation> 
class binder1st
  : public unary_function<typename _Operation::second_argument_type,
                          typename _Operation::result_type> {
protected:
  _Operation op;
  typename _Operation::first_argument_type value;
public:
  binder1st(const _Operation& __x,
            const typename _Operation::first_argument_type& __y)
      : op(__x), value(__y) {}
  typename _Operation::result_type
  operator()(const typename _Operation::second_argument_type& __x) const {
    return op(value, __x); 
  }
};



2.2 unary_compose


将两个属于unary_function的函数对象级联。假设函数对象分别为op1op2, 那么unary_compose的执行结果为op1(op2(x))


因此unary_compose的输入参数类型为_Operation2::argument_type,输出参数类型为_Operation1::result_type。并且要求在类型上_Operation2::result_type可隐式转换成_Operation1::argument_type


template <class _Operation1, class _Operation2>
class unary_compose
  : public unary_function<typename _Operation2::argument_type,
                          typename _Operation1::result_type> 
{
protected:
  _Operation1 _M_fn1;
  _Operation2 _M_fn2;
public:
  unary_compose(const _Operation1& __x, const _Operation2& __y) 
    : _M_fn1(__x), _M_fn2(__y) {}
  typename _Operation1::result_type
  operator()(const typename _Operation2::argument_type& __x) const {
    return _M_fn1(_M_fn2(__x));
  }
};




2.3 pointer_to_unary_function


将一个指向一元函数的指针封装成一元函数对象。

template <class _Arg, class _Result>
class pointer_to_unary_function : public unary_function<_Arg, _Result> {
protected:
  _Result (*_M_ptr)(_Arg);
public:
  pointer_to_unary_function() {}
  explicit pointer_to_unary_function(_Result (*__x)(_Arg)) : _M_ptr(__x) {}
  _Result operator()(_Arg __x) const { return _M_ptr(__x); }
};




2.4 mem_fun_t


将类内非静态成员函数封装成一元函数对象。


对于mem_fun_t对象,其构造时记录指向类_Tp内非静态成员函数(输入参数个数为零)的指针,执行时,传入指向_Tp对象的指针__p,调用(__p->*_M_f)()


在C++中,函数指针类似这种形式:int (*f)(int, double)f指向一个入参为int, double,出参为int的函数。调用函数指针f时,只需指定输入参数。

而成员函数指针类似于:int (T::*mf)(int, double)mf指向一个入参为int, double, 出参为int的成员函数。调用成员函数指针时,除了需指定输入参数外,还需指定T对象指针,因为类中非静态成员函数是和该类对象绑定的。


template <class _Ret, class _Tp>
class mem_fun_t : public unary_function<_Tp*,_Ret> {
public:
  explicit mem_fun_t(_Ret (_Tp::*__pf)()) : _M_f(__pf) {}
  _Ret operator()(_Tp* __p) const { return (__p->*_M_f)(); }
private:
  _Ret (_Tp::*_M_f)();
};



其他变体:


  • const_mem_fun_t: 将类内非静态的const成员函数封装成一元函数对象


  • mem_fun_ref_t: 类似mem_fun_t,区别在于调用mem_fun_t时传入的是类对象指针,而调用mem_fun_ref_t时传入的是类对象引用。


  • const_mem_fun_ref_t: const_mem_fun_tmem_fun_ref_t的组合




2.5 其他


  • negate: 取负操作。实现中对_Tp对象执行operator-操作,因此negate的输入模板参数不止为数字,也可是重载了operator-操作符的其他任何类型。


  • logical_not: 逻辑取反。函数对象输入参数类型为_Tp, 输出参数类型为bool。实现中对_Tp对象执行operator!操作,对象可重载该操作符。


  • unary_negate: 同negate相似,只不过带了一个判断条件。输入参数__x, 返回布尔值!_M_pred(__x)




3 二元函数对象


二元函数对象接受两个参数,返回一个结果值。


STL中定义的所有二元函数对象都继承自binary_function, 其中


  • first_argument_type: 第一个输入参数类型


  • second_argument_type: 第二个输入参数类型


  • result_type: 输出参数类型


template <class _Arg1, class _Arg2, class _Result>
struct binary_function {
  typedef _Arg1 first_argument_type;
  typedef _Arg2 second_argument_type;
  typedef _Result result_type;
};





3.1 mem_fun1_t


mem_fun_t类似,将一个成员函数指针封装成函数对象。区别在于mem_fun_t中成员函数入参个数为零,而mem_fun1_t中成员函数入参个数为1,这样的话调用mem_fun1_t时,需同时传入成员函数的入参和成员函数所在类对象指针。



其他变体:const_mem_fun1_t/mem_fun1_ref_t/const_mem_fun1_ref_t,功能与mem_fun_t的变体类似,这里跳过




3.2 其他


以下二元函数对象顾名思义,本质上是对各种操作符的封装。


plus
minus
multiplies
divides
modulus
equal_to
not_equal_to
greater
less
greater_equal
less_equal
logical_and
logical_or
logical_not


binary_compose: 功能同unary_compose。区别在于将三个二元函数对象级联,输出__fn1(__fn2(__x), __fn3(__x))

相关文章
|
8月前
|
存储 算法 C++
【C++】STL的基本用法
【C++】STL的基本用法
86 0
|
存储 编译器 C++
vector使用及简单实现【STL】【附题】
vector使用及简单实现【STL】【附题】
48 0
|
6月前
|
存储 算法 程序员
C++基础知识(八:STL标准库(Vectors和list))
C++ STL (Standard Template Library标准模板库) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues(队列), lists(链表), 和 stacks(栈)等. STL容器的提供是为了让开发者可以更高效率的去开发,同时我们应该也需要知道他们的底层实现,这样在出现错误的时候我们才知道一些原因,才可以更好的去解决问题。
|
存储 算法 编译器
【C++STL】“vector“用法 入门必备 超详细
【C++STL】“vector“用法 入门必备 超详细
|
存储 算法 安全
【C++STL精讲】vector的基本使用与常用接口
【C++STL精讲】vector的基本使用与常用接口
342 0
|
存储 算法 C++
【C++】STL —— vector基本使用
【C++】STL —— vector基本使用
163 0
【C++】STL —— vector基本使用
|
安全 API C++
STL源码分析--vector
STL源码分析--vector
186 0
STL源码分析--vector
|
C++ 容器
STL源码分析--deque
STL源码分析--deque
137 0
STL源码分析--deque
|
算法 C++ 索引
STL源码分析--algorithm
STL源码分析--algorithm
138 0
|
编译器 测试技术 对象存储
STL源码分析--traits
STL源码分析--traits
307 0