STL源码分析--functional
Posted 后端技术小屋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
的函数对象级联。假设函数对象分别为op1
和op2
, 那么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_t
和mem_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))
以上是关于STL源码分析--functional的主要内容,如果未能解决你的问题,请参考以下文章
STL源码拆解基于源码分析forward_lsit容器实现(详细!)
STL源码拆解基于源码分析forward_lsit容器实现(详细!)
STL源码拆解基于源码分析forward_lsit容器实现(详细!)
STL源码拆解基于源码分析forward_lsit容器实现(详细!)
Android 插件化VirtualApp 源码分析 ( 目前的 API 现状 | 安装应用源码分析 | 安装按钮执行的操作 | 返回到 HomeActivity 执行的操作 )(代码片段