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))

相关文章
|
存储 安全 NoSQL
【C++ 异常 】深入了解C++ 异常机制中的 terminate()处理 避免不必要的错误(二)
【C++ 异常 】深入了解C++ 异常机制中的 terminate()处理 避免不必要的错误
1012 1
|
存储 安全 算法
【C++ 17 新特性 】拥抱现代C++:深入C++17特性以获得更高效、更安全的代码
【C++ 17 新特性 】拥抱现代C++:深入C++17特性以获得更高效、更安全的代码
4974 1
|
Java 程序员
使用 Callable 和 Future 创建线程
使用 Callable 和 Future 创建线程
419 0
|
1天前
|
存储 机器学习/深度学习 人工智能
打破硬件壁垒!煎饺App:强悍AI语音工具,为何是豆包AI手机平替?
直接上干货!3000 字以上长文,细节拉满,把核心功能、使用技巧和实测结论全给大家摆明白,读完你就知道这款 “安卓机通用 AI 语音工具"——煎饺App它为何能打破硬件壁垒?它接下来,咱们就深度拆解煎饺 App—— 先给大家扒清楚它的使用逻辑,附上“操作演示”和“🚀快速上手不踩坑 : 4 条核心操作干货(必看)”,跟着走零基础也能快速上手;后续再用真实实测数据,正面硬刚煎饺 App的语音助手口令效果——创建京东「牛奶自动下单神器」口令 ,从修改口令、识别准确率到场景实用性,逐一测试不掺水,最后,再和豆包 AI 手机语音助手的普通版——豆包App对比测试下,简单地谈谈煎饺App的能力边界在哪?
|
3天前
|
云安全 监控 安全
|
8天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
1063 5
|
10天前
|
机器学习/深度学习 人工智能 数据可视化
1秒生图!6B参数如何“以小博大”生成超真实图像?
Z-Image是6B参数开源图像生成模型,仅需16GB显存即可生成媲美百亿级模型的超真实图像,支持中英双语文本渲染与智能编辑,登顶Hugging Face趋势榜,首日下载破50万。
710 42

热门文章

最新文章