您的位置:首页 > 其它

STL中的约束器相关总结

2012-11-14 13:01 232 查看
摘要: STL里有仿函数的概念,而在应用仿函数的时候,仿函数与仿函数之间的适配引出了约束器的概念。这一节主要叙述一下一元函数对象基类unary_function、二元函数对象基类binary_function,以及两个约束器binder1st与binder2nd,同时给出一个场景,分析实现原理。

1:template <class Arg, class Result> struct unary_function;

2:template <class Arg1, class Arg2, class Result> struct binary_function;

3: template <class Operation> class binder1st;

4: template <class Operation> class binder2nd;

5: template <class Operation, class T>

binder2nd<Operation> bind2nd (const Operation& op, const T& x);

6: template <class Operation, class T>

binder1st<Operation> bind1st (const Operation& op, const T& x);

unary_function是一元函数对象的基类,unary_function作为一个基类并没有实现operator(),仅仅含有两个数据成员,operator()是由子类根据具体情况实现的。binary_function则是二元函数对象的基类,同样没有实现operator().

[cpp] view
plaincopy

template <class Arg, class Result>

struct unary_function {

typedef Arg argument_type;

typedef Result result_type;

};

// unary_function example

#include <iostream>

#include <functional>

using namespace std;

struct IsOdd : public unary_function<int,bool> {

bool operator() (int number) {return (number%2==1);}

};

int main () {

IsOdd IsOdd_object;

IsOdd::argument_type input;

IsOdd::result_type result;

cout << "Please enter a number: ";

cin >> input;

result = IsOdd_object (input);

cout << "Number " << input << " is " << (result?"odd":"even") << ".\n";

return 0;

}

[cpp] view
plaincopy

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 example

#include <iostream>

#include <functional>

using namespace std;

struct Compare : public binary_function<int,int,bool> {

bool operator() (int a, int b) {return (a==b);}

};

int main () {

Compare Compare_object;

Compare::first_argument_type input1;

Compare::second_argument_type input2;

Compare::result_type result;

cout << "Please enter first number: ";

cin >> input1;

cout << "Please enter second number: ";

cin >> input2;

result = Compare_object (input1,input2);

cout << "Numbers " << input1 << " and " << input2;

if (result)

cout << " are equal.\n";

else

cout << " are not equal.\n";

return 0;

}

binder1st 与 binder2nd
的作用都是由二元函数对象得到一个一元函数对象,他们是"函数对象的适配器",其中binder1st
将第一个参数固定为一个固定的数值,binder2nd 将第二个参数固定为一个固定的数值。具体使用的时候,将某一个参数绑定为操作的第一个或者第二个参数,要根据操作语义而定,见如下示例。而bind2nd 与bind1st就是为了产生这两种对象而存在的。

[cpp] view
plaincopy

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

};

// binder1st example

#include <iostream>

#include <functional>

#include <algorithm>

using namespace std;

int main () {

binder1st < equal_to<int> > equal_to_10 (equal_to<int>(),10); // 这里将10版定位(equal_to<int>())操作的第一个参数

int numbers[] = {10,20,30,40,50,10};

int cx;

cx = count_if (numbers,numbers+6,equal_to_10);

cout << "There are " << cx << " elements equal to 10.\n";

return 0;

}

[cpp] view
plaincopy

template <class Operation> class binder2nd

: public unary_function <typename Operation::first_argument_type,

typename Operation::result_type>

{

protected:

Operation op;

typename Operation::second_argument_type value;

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

};

// binder2nd example

#include <iostream>

#include <functional>

#include <algorithm>

using namespace std;

int main () {

binder2nd < less<int> > IsNegative (less<int>(),0); // 这里将0绑定为(less<int>())操作的第二个参数

int numbers[] = {10,-20,-30,40,-50};

int cx;

cx = count_if (numbers,numbers+5,IsNegative);

cout << "There are " << cx << " negative elements.\n";

return 0;

}

下面给出一个场景分析:

现在定义一个函数对象如下inserter
,完成的功能是向vector中插入数据,如下可见在实际使用的时候传递两个参数。

[cpp] view
plaincopy

struct inserter {

public:

void operator()(double n, vector<double> & v) { v.push_back(n); }

};

inserter f;

vector<double> vd;

f(1.0, vd); //两个参数

如果现在有一个算法append是如下定义的,向容器中添加一些数据成员。

[cpp] view
plaincopy

template<typename Functor>

void append(Functor f) {

double x;

while(cin>>x)

f(x);

}

这时,你的insert就用不上了,因为append的functor只要求一个参数。如果你的inserter本来是一个很复杂的操作,那么如果重写一个就很麻烦。不过有一个简单的办法是再定义一个inserter_adapter。

[cpp] view
plaincopy

template<typename Functor>

struct inserter_adapter {

inserter_adapter(const Functor& f, vector<double>& v)

:f_(f), v_(v) {}

void operator()(double x) { f_(x, v_);}

Functor f_;

vector<double>& v_;

};

inserter f;

vector<double> vd;

inserter_adapter ia(f, vd); //将vd绑定到操作符f的第二个参数上

append(ia);

由以上的场景分析,可以看出inserter_adapter 充当了一个适配器的角色,解决了二元函数对象无法适应一元函数对象操作的情况。因为inserter_adapter
将容器参数对象绑定到了操作符的第二个参数上。

以上方案实现的是将二元函数对象转化为一元函数对象,这种转化是通过绑定一个操作对象。而在STL中,这种参数绑定操作可以通过以上介绍的binder2nd或者binder1st实现。

[cpp] view
plaincopy

struct inserter :public std::binary_function<double, vector<double>&, void> {

public:

void operator()(double n, vector<double> & v) { v.push_back(n); }

};

template<typename Functor>

void append(Functor f) {

double x;

while(cin>>x)

f(x);

}

inserter f;

vector<double> vd;

append(std::bind2nd(f, vd)); //bind2nd创建了一个binder2nd对象,将参数vd绑定到操作符f的第二个参数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: