Ch7 仿函数(另名 函数对象)
7.1 仿函数概观
仿函数在调用者可以像函数一样地被调用,在被调用者则以对象所定义的function call operator扮演函数的实质角色。
就实现观点而言,仿函数其实就是一个“行为类似函数”的对象。为了能够“行为类似函数”,其类别定义中必须自定义function call运算子(operator()),拥有这样的运算子之后,我们就可以在仿函数的对象后面加上一对小括号,以此调用仿函数所定义的operator(),如:
... greater<int> ig; ig(4,6); greater<int>() (4,6); //先产生一个临时对象,再指定参数 ...任何应用程序欲使用STL内建的仿函数,都必须含入<functional>头文件,SGI则将它们实际定义于<stl_function.h>文件中。
7.2 可配接(Adaptable)的关键
STL仿函数应该有能力被函数配接器修饰,为了拥有配接能力,每一个仿函数必须定义自己的相应型别,以便让配接器能够取出,获得仿函数的某些信息。
相应型别都只是一些typedef,所有必要操作在编译期就全部完成了,对程序的执行效率没有任何影响,不带来任何额外负担。
7.2.1 unary_function(一元函数)
unary_function用来呈现一元函数的参数型别和返回值型别:
//STL规定,每个Adaptable Unary Function都应该继承此类别 template <class Arg, class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; };一旦某个仿函数继承了unary_function,其用户便可以这样取得该仿函数的参数型别,并以相同手法取得其返回值型别:
//以下仿函数继承了unary_function template <class T> struct negate : public unary_function<T, T>{ T operator() (const T& x ) const { return -x; } }; //以下配接器用来表示某个仿函数的逻辑负值 template <class Predicate> class unary_negate ... public: bool operator() (const typename Predicate::argument_type& x) const { ... } };
7.2.2 binary_function(二元函数)
binary_function用来呈现二元函数的第一参数型别、第二参数型别,以及返回值型别:
//STL规定,每个Adaptable Unary Function都应该继承此类别 template <class Arg1, class Arg2, class Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; };一旦某个仿函数继承了binary_function,其用户便可以这样取得该仿函数的各种参数型别:
//以下仿函数继承了binary_function template <class T> struct plus : public binary_function<T, T, T>{ T operator() (const T& x ,const T& y) const { return x+y; } }; //以下配接器用来将某个二元仿函数转化为一元仿函数 template <class Operation> class binder1st ... protected: Operation op; typedef Operation::first_argument_type value; public: typedef Operation::result_type bool operator() (const typename Operation::second_argument_type& x) const { ... } };
7.3 算术类(Arithmetic)仿函数
以下是STL内建的“算术类仿函数”,除了“否定”运算为一元运算,其他都是二元运算。
- 加法:plus<T>
- 减法:minus<T>
- 乘法:multiplies<T>
- 除法:divides<T>
- 模取(modulus):modulus<T>
- 否定(negation):negate<T>
证同元素(identity element):
所谓“运算op的证同元素”,意思是数字A若与该元素做op运算,会得到A自己。
(加法的证同元素为0,因为任何元素加上0仍为自己;同理,乘法的证同元素为1。)
7.4 关系运算类(Relational)仿函数
以下是STL内建的“关系运算类仿函数”,每一个都是二元运算。
- 等于(equality):equal_to<T>
- 不等于(inequality):not_equal_to<T>
- 大于(greater than):greater<T>
- 大于或等于(greater than or equal):greater_equal<T>
- 小于(less than):less<T>
- 小于或等于(less than or equal):less_equal<T>
7.5 逻辑运算类(Logical)仿函数
以下是STL内建的“逻辑运算类仿函数”,其中And 和Or 为二元运算,Not 为一元运算。
- 逻辑运算 And:logical_and<T>
- 逻辑运算 Or:logical_or<T>
- 逻辑运算 Not:logical_not<T>
7.6 证同(identify)、选择(select)、投射(project)
//证同函数。 //任何数值通过此函数后,不会有任何改变 //此式运用于<stl_set.h>,用来指定RB-tree所需的KeyOfValue op //那是因为set元素的键值即实际值,所以采用identity template <class T> struct identity : public unary_function<T, T> { const T& operator() (const T& x) const { return x; } }; //选择函数1。 //接收一个pair,传回其第一元素 //此式用于<stl_map.h>,用来指定RB-tree所需的KeyOfValue op //由于map是以pair元素的第一元素为其键值,所以采用select1st template <class Pair> struct select1st : public unary_function<Pair, typename Pair::first_type> { const typename Pair::first_type& operator() (const Pair& x) const { return x.first; } }; //选择函数2。 //接收一个pair,传回其第二元素 template <class Pair> struct select2nd : public unary_function<Pair, typename Pair::second_type> { const typename Pair::second_type& operator() (const Pair& x) const { return x.second; } }; //投射函数1。 //传回第一参数,忽略第二参数 template <class Arg1, class Arg2> struct project1st : public binary_fucntion<Arg1, Arg2, Arg1>{ Arg1 operator() (const Arg1& x, const Arg2&) const { return x; } }; //投射函数2. //传回第二参数,忽略第一参数 template <class Arg1, class Arg2> struct project2nd : public binary_function<Arg1, Arg2, Arg2>{ Arg2 operator() (const Arg1&, const Arg2& y) const { return y; } };