1、函数对象
定义了调用操作符的类型,为类类型的对象提供重载函数的调用操作符,其对象称之为函数对象。
(1)函数对象使用方式
代码如下:
#include <iostream>
using namespace std;
//函数对象
template<class T>
struct IsOdd
{
bool operator() (T x){return (x & 1)?true: false;}
};
//函数功能 : 调整数组顺序使奇数位于偶数前面
//函数参数 : pArray指向数组的指针,nLen为数组长度
//返回值 : 无
template <class T, class F>
void PartionArray(T *pArray, int nLen, F func)
{
int i = -1;
for(int j = 0; j < nLen; j++)
{
if(func(pArray[j])) //满足调整条件
{
i++;
T tmp = pArray[j];
pArray[j] = pArray[i];
pArray[i] = tmp;
}
}
}
//测试用例
int main()
{
short a[] = {1,2,3,4,5,6};
long b[] = {1,2,3,4,5,6};
PartionArray(a, 6, IsOdd<short>());
PartionArray(b, 6, IsOdd<long>());
return 0;
}
(2)函数指针处理
与函数对象的处理方式不同,函数指针处理方式如下。
代码如下:
bool IsOdd(int x)
{
return (x & 1)? true: false;
}
//函数功能 : 调整数组顺序使奇数位于偶数前面
//函数参数 : pArray指向数组的指针,nLen为数组长度
//返回值 : 无
void PartionArray(int *pArray, int nLen, bool (*func)(int))
{
int i = -1;
for(int j = 0; j < nLen; j++)
{
if(func(pArray[j])) //满足调整条件
{
i++;
int tmp = pArray[j];
pArray[j] = pArray[i];
pArray[i] = tmp;
}
}
}
(3)stl的函数对象
相比函数指针,函数对象能很好的满足STL的抽象要求。STL中的函数对象是与STL的算法联系在一起。
(3-1)stl函数对象定义
STL定义了两个类,作为一元操作和二元操作的基类,这两个基类仅仅是使用了内嵌型别技术。
//用来定义一元操作的参数类别和返回值类别
template <class Arg, class Result>
struct unary_function {
typedef Arg argument_type; //内嵌型别技术
typedef Result 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;
};
2)函数对象使用类型
包含一元和二元操作的函数对象。
代码如下:
//一元操作,就两个
template <class T>
struct negate : public unary_function<T, T> {
T operator()(const T& x) const { return -x; }
};
template <class T>
struct logical_not : public unary_function<T,bool> {
bool operator()(const T& x) const { return !x; }
};
//加减乘除取模
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 T>
struct minus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x - y; }
};
template <class T>
struct multiplies : public binary_function<T, T , T> {
T operator()(const T& x, const T& y) const { return x * y; }
};
template <class T>
struct divides : public binary_function<T ,T, T> {
T operator()(const T& x, const T& y) const { return x / y; }
};
template <class T>
struct modulus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x % y; }
};
//关系运算
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 <class T>
struct not_equal_to : public binary_function<T, T,bool> {
bool operator()(const T& x, const T& y) const { return x != y; }
};
template <class T>
struct greater : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x > y; }
};
template <class T>
struct less : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x < y; }
};
template <class T>
struct greater_equal : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x >= y; }
};
template <class T>
struct less_equal : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x <= y; }
};
//逻辑运算
template <class T>
struct logical_and : public binary_function<T, T, bool>{
bool operator()(const T& x, const T& y) const { return x && y; }
};
template <class T>
struct logical_or : public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x || y; }
};
(3-1)stl函数对象使用
数组排序,代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a[] = {1,3,2,4,5,7};
sort(&a[0], &a[6]);
for(int i = 0; i < 6; i++)
cout<<a[i]<<' ';
cout<<endl;
return 0;
}
这个排序算法默认是递增排序,如果是递减排序,就在函数实参中加入一个函数对象即可。
#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;
int main()
{
int a[] = {1,3,2,4,5,7};
sort(&a[0], &a[6], greater<int>());
for(int i = 0; i < 6; i++)
cout<<a[i]<<' ';
cout<<endl;
return 0;
}
2、 函数适配器
函数适配器是复杂点的函数对象,用于特化和扩展一元和二元函数对象。
(1) 函数适配器使用
函数适配器类型包括:
1)绑定器,通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数。
2)求反器,它将谓词函数对象的真值求反。
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> vec(10, 1);
int count1 = count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10)); //求容器中小于等于10的元素个数
int count2 = count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10))); //求容器中不小于等于10的元素个数,正好是上面结果的取反
cout<<count1<<' '<<count2<<endl; //10 0
return 0;
}
(2)绑定器和求反器
(2-1)绑定器
如 binder1st 绑定器类型,它的模板中只有一个形参,它继承自unary_function模板类型,有两个形参。第一个模板实参是个函数对象,继承自unary_function或binary_function;第二个模板实参是操作的对象,也就是值。
代码如下:(根据STL源码整理的)
//绑定第一个参数
template <class Operation>
class binder1st: public unary_function<typename Operation::second_argument_type, typename Operation::result_type> {
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); //固定第一个参数
}
protected:
Operation op;
typename Operation::first_argument_type value;
};
//绑定第二个参数
template <class Operation>
class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {
public:
binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) {}
typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const {
return op(x, value); //固定第二个参数
}
protected:
Operation op;
typename Operation::second_argument_type value;
};
//绑定器对外封装的接口
template <class Operation, class T>
inline binder1st<Operation> bind1st(const Operation& fn, const T& x) {
typedef typename Operation::first_argument_type Arg1_type;
return binder1st<Operation>(fn,Arg1_type(x));
}
template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {
typedef typename Operation::second_argument_type Arg2_type;
return binder2nd<Operation>(fn, Arg2_type(x));
}
(2-2)求反器
代码如下
//一元操作求反
template <class Predicate>
class unary_negate: public unary_function<typename Predicate::argument_type, bool> {
protected:
Predicate pred;
public:
explicit unary_negate(const Predicate& x) : pred(x) {}
bool operator()(const typename Predicate::argument_type& x) const {
return !pred(x);
}
};
//二元操作求反
template <class Predicate>
class binary_negate : public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type,bool> {
protected:
Predicate pred;
public:
explicit binary_negate(const Predicate& x) : pred(x) {}
bool operator()(const typename Predicate::first_argument_type& x, const typename Predicate::second_argument_type& y) const {
return !pred(x, y);
}
};
//外部接口
template <class Predicate>
inline unary_negate<Predicate> not1(const Predicate& pred)
{
return unary_negate<Predicate>(pred);
}
template <class Predicate>
inline binary_negate<Predicate> not2(const Predicate& pred)
{
return binary_negate<Predicate>(pred);
}
3、函数对象与算法
算法count_if(vec.begin(), vec.end(),bind2nd(less_equal<int>(), 10),count1)具体执行:
1)执行bind2nd(less_equal<int>(),10)这个函数,这个函数会返回一个binder2nd的函数对象.
注意构造这个函数对象的时候,binder2nd(constOperation& x, const typename Operation::second_argument_type& y) :op(x), value(y) {} 。
第二个参数value的值设置为10,而第一个参数op设置成less_equal<int>()这个函数对象。
2)在count_if中,pred(*first)其实就是binder2nd中的运算,而这个运算的第二个参数是固定的,也就是10,所以pred只传递了一个实参进去就可以了。3)符合pred 函数对象条件的,记录到参数n中
完整的测试代码如下:(根据stl修改的)
#include <iostream>
#include <vector>
using namespace std;
//count_if函数
template <class InputIter, class Predicate, class Size>
void count_if(InputIter first, InputIter last, Predicate pred, Size& n) {
for ( ; first != last; ++first)
if (pred(*first))
++n;
}
template <class InputIter, class Predicate>
typename iterator_traits<InputIter>::difference_type count_if(InputIter first, InputIter last, Predicate pred) {
typename iterator_traits<InputIter>::difference_type n = 0;
for ( ; first != last; ++first)
if (pred(*first))
++n;
return n;
}
//用来定义一元操作的参数类别和返回值类别
template <class Arg, class Result>
struct unary_function {
typedef Arg argument_type;
typedef Result 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;
};
//本测试之用到关系函数对象
template <class T>
struct less_equal : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x <= y; }
};
//绑定第二个参数
template <class Operation>
class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {
public:
binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) { cout<<"binder2nd Constructor"<<endl; }
typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const {
cout<<"binder2nd's operator()"<<endl;
return op(x, value); //固定第二个参数
}
protected:
Operation op;
typename Operation::second_argument_type value;
};
//外部接口
template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {
typedef typename Operation::second_argument_type Arg2_type;
return binder2nd<Operation>(fn, Arg2_type(x));
}
//一元操作求反
template <class Predicate>
class unary_negate: public unary_function<typename Predicate::argument_type, bool> {
protected:
Predicate pred;
public:
explicit unary_negate(const Predicate& x) : pred(x) { cout<<"unary_negate Constructor"<<endl; }
bool operator()(const typename Predicate::argument_type& x) const {
cout<<"unary_negate's operator()"<<endl;
return !pred(x);
}
};
//外部接口
template <class Predicate>
inline unary_negate<Predicate> not1(const Predicate& pred)
{
return unary_negate<Predicate>(pred);
}
//测试程序
int main()
{
vector<int> vec(10, 1);
int count1 = 0, count2 = 0;
count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10),count1); //求容器中小于等于10的元素个数
count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10)),count2); //求容器中不小于等于10的元素个数,正好是上面函数的取反
cout<<count1<<' '<<count2<<endl; //10 0
return 0;
}