boost operators

operators:
 很多操作符可以从其他的操作符自动推导出来,例如a!=b可以是!(a==b),a>=b可以是!(a<b).因此原则上只需要定义少量的基本操作符,其他的操作符就可以用逻辑组合实现。
 在C++98标准的std::rel_ops名字空间里提供了四个模板比较操作符!=,>,<=,>=,只需要为类定义了==和<操作符,那么这四个操作符就可以自动实现。
示例:
#include <iostream>
#include <assert.h>
#include <boost/logic/tribool.hpp>
#include <boost/logic/tribool_io.hpp>
#include <utility>
using namespace boost;
using namespace std;
class demo_class
{
public:
 demo_class(int n): x(n){}
 int x;
 friend bool operator<(const demo_class& l, const demo_class &r)
 {  return l.x < r.x; }
};
int main()
{
 demo_class a(10), b(20);
 using namespace std::rel_ops; //打开std::rel_ops名字空间
 cout<< (a < b) <<endl;   //自定义的<操作符
 cout << (b>= a)<<endl;   //>=等操作符被自动实现
 system("pause");
 return 0;
}

 但std::rel_ops的解决方案过于简单,除了比较操作符,还有很多其他的操作符重载标准库没有给出解决方案,而且使用这些操作符需要用using语句导入std::rel_ops名字空间,不方便,也会带来潜在的冲突风险。

 boost.operators库因此应运而生。它采用类似std::rel_ops的实现手法,允许用户在自己的类里仅定义少量的操作符(如<),就可方便地自动生成其他操作符重载,而且保证正确的语义实现。

#include <boost/operators.hpp>
using namespace boost;

基本运算概念:
 operators库是由多个类组成的,分别用来实现不同的运算概念,比如less_than_comparable定义了<系列操作符,left_shiftable定义了<<系列操作符。operator中的概念非常多,囊括了c++中大部分操作符重载,这里介绍一些最常用的算术操作符:
 【1】equality_comparable: 要求提供==,可自动实现!=,相等语义;
 【2】less_than_comparable: 要求提供<,可自动实现>,<=,>=;
 【3】addable:   要求提供+=,自动实现+;
 【4】subtractable:  要求提供-=,可自动实现-;
 【5】incrementable:  要求提供前置++,可自动实现后置++;
 【6】decrementable:  要求提供前置--,可自动实现后置--;
 【7】equivalent:  要求提供<,可自动实现==; 
这些概念在库中以同名类的形式提供,用户需要以继承的方式来使用它们,继承的修饰符并不重要(private,public都可以),因为operator库里的类都是空类,没有成员变量和成员函数,仅定义了数个友元操作符函数。

 如果要同时实现多个运算概念则可以使用多重继承技术,把自定义类作为多个概念的子类。

算术操作符的用法:
#include <iostream>
#include <assert.h>
#include <boost/operators.hpp>
using namespace boost;
using namespace std;
class point:boost::less_than_comparable<point>, boost::equality_comparable<point>
{
 int x, y, z;
public:
 explicit point(int a = 0, int b = 0, int c = 0):x(a),y(b),z(c){}
 void print() const
 {  cout<< x<< "," << "," << z<<endl; }

 friend bool operator<(const point& l, const point &r)
 {
  return (l.x * l.x + l.y *l.y + l.z * l.z <
    r.x * r.x + r.y * r.y + r.z * r.z);
 }
 friend bool operator==(const point& l, const point &r)
 { return r.x == l.x && r.y == l.y && r.z == l.z; }
};
int main()
{
 point p0, p1(1, 2, 3), p2(3, 0, 5), p3(3, 2, 1);
 assert(p0 < p1 && p1 < p2);
 assert(p2 > p0);
 assert(p1 <= p3);
 assert(!(p1 < p3) && !(p1 > p3));
 assert(p1 != p2);
 system("pause");
 return 0;
}
 less_than_comparable作为基类的用法可能稍微有点奇怪,它把子类point作为了父类的模板参数:less_than_comparable<point>,看起来好像是个“循环继承”,实际上,point类作为less_than_comparable的模板类型参数,只是用来实现内部的比较操作符,用作操作符函数的类型,没有任何继承关系,less_than_comparable生成的代码可以理解成这样:
//template<T = point>
struct less_than_comparable
{
 friend bool operator >= (const point &x, const point &y);
 { return !(x<y); }
}
 poing类定义了一个友元operator<操作符,然后其余的>,<=,>=就由less_than_comparable自动生成。

 在使用operators库时要注意一点,模板类型参数必须是子类自身,特别是当子类本身也是个模板类的时候,不要错写成子类的模板参数或者子类不带模板参数的名称,否则会造成编译错误。
示例:
temolate<typename T> class point{...}
template<typename T>  class point:boost::less_than_comparable<T> //error
template<typename T>  class point:boost::less_than_comparable<point> //error
template<typename T>  class point:boost::less_than_comparable<point<T>> //ok

基类链:
 operators库使用泛型编程的“基类链”技术解决了多重继承的问题,这种技术通过模板把多继承转换为链式的单继承。

 operator库的操作符模板类除了接受子类作为比较类型外,还可以接受另外一个类,作为它的父类,由此可以无限串联链接在一起:
demo:x<demo, y<demo, z<demo,...>>>
使用基类链技术,point类的基类部分可以这样:
boost::less_than_comparable<point, boost::equality_comparable<point>>//是一个有很大模板参数列表的类。

如果在为point类增加加法和减法定义,继承列表就是:
class point:less_than_comparable<point, equality_compareable<point, addable<point, subtractable<point>>>>{...}

复合运算概念:
 operators库使用基类链把一些简单的运算概念组合成了复杂的概念,即复合运算,复合运算不仅简化了代码的编写,也可以避免用户代码中基类链过程的问题。
 operator库提供的常用复合运算概念:
 【1】totally_ordered:全序概念,组合了equality_comparable和less_than_comparable;
 【2】additive:可加减概念,组合了addable和subtractable;
 【3】multiplicative:可乘除概念,组合了additive和multiplicative
 【4】unit_stoppable:可步进概念组合了incrementable和decrementable;
使用复合运算概念,point类只需要很少的代码就可以很容易地获得完全的算术运算能力:

示例:
#include <iostream>
#include <vector>
#include <assert.h>
#include <boost/operators.hpp>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
using namespace boost;
using namespace std;
class point:totally_ordered<point,  //全序比较运算
   additive<point>>   //可加减运算
{
 int x, y, z;
public:
 explicit point(int a = 0, int b = 0, int c = 0):x(a),y(b),z(c){}
 void print() const
 {  cout<< x<< "," << y << "," << z<<endl; }

 friend bool operator<(const point& l, const point &r)
 {
  return (l.x * l.x + l.y *l.y + l.z * l.z <
    r.x * r.x + r.y * r.y + r.z * r.z);
 }
 friend bool operator==(const point& l, const point &r)
 { return r.x == l.x && r.y == l.y && r.z == l.z; }
 point & operator+=(const point &r) //支持addable概念
 {
  x += r.x;
  y += r.y;
  z += r.z;
  return *this;
 }
 point & operator-=(const point &r) //支持subtractable概念
 {
  x -= r.x;
  y -= r.y;
  z -= r.z;
  return *this;
 }
};
int main()
{
 point p0, p1(1,2,3),p2(5,6,7),p3(3,2,1);
 using namespace boost::assign;
 vector<point> v = (list_of(p0),p1,p2,p3);
 BOOST_AUTO(pos,std::find(v.begin(), v.end(), point(1, 2, 3)));
 pos->print();
 (p1 + p2).print();
 (p3 - p1).print();
 assert((p2 -p2) == p0);
 system("pause");
 return 0;
}

相等与等价:
 operators库使用equality_comparable和equivalent明确地区分了相等于等价的概念.equality_comparable基于==,equivalent则基于<,但让人困扰的是它们最终都提供了操作符==,表现相同但涵义非常不同.

解引用操作符: 
 operators库使用dereferenceable提供了对解引用操作符*,->的支持,它的用法与之前介绍的算术操作符不太相同.
 dereferenceable有三个模板参数:
 【1】第一个参数是要实现operator->的子类,它的含义与算术操作符相同
 【2】第二个参数是operator->所返回的类型,也就是指针类型,通常应该是T*;
 【3】最后一个参数是用于基类链技术的父类;
 dereferenceable类要求子类提供operator*,会自动实现operator->,注意它的operator->函数的定义,在使用dereferenceable时必须使用public继承,否则operator->将会成为类的私有成员函数,外界无法访问.
 由于dereferenceable实现了解引用操作符的语义,因此它可以用于实现自定义的智能指针类,或者是实现代理模式,包装代理某些对象。
 
示例:下面的代码实现了一个简单的智能指针类my_smart_ptr,它public继承了dereferenceable,重载operator*并自动获得了operator->的定义:
template<typename T>
class my_smart_ptr:
 public dereferenceable<my_smart_ptr<T>, T*>//必须public继承
{
 T *p;  //内部保存的指针
public:
 my_smart_ptr(T *x):p(x){} //构造函数
 ~my_smart_ptr(){delete p;} //析构函数
 T& operator*() const  //operator*定义,必须是常函数
 { return *p;}
};

//my_smart_ptr的用法就像是scoped_ptr;
my_smart_ptr<string> p(new string("123"));
assert(p->size() == 3);

下标操作符:
 operators库使用indexable提供了下标操作符[]的支持,它也属于解引用的范畴,用法与dereferenceable很相似:参数列表中的T,B含义与dereferenceable的T,B含义相同,分别是子类类型和基类链的父类类型。
 参数I是下标操作符的值类型,通常应该是整数,但也可以是其他类型,只要它能够与类型T做加法操作。参数R是operator[]的返回值类型,通常应该是一个类型的引用。
indexable要求子类提供一个operator+(T, I)的操作定义,类似于一个指针的算术运算,它应该返回一个迭代器类型,能够使用operator*解引用得到R类型的值。

 与dereferenceable的例子类似,使用一个my_smart_array类来模仿实现scoped_array,my_smart_array从indexable公开继承,下标操作符类型是int,operator[]的返回值类型是T&;

template<typename T>
class my_smart_array:
 public indexable<my_smart_array<T>, int, T&>
{
 T *p;  //保存动态数组指针
public:
 typedef my_smart_array<T> this_type;
 typedef T* iter_type;  //迭代器类型
 my_smart_array(T *x):p(x){} //构造函数
 ~my_smart_array(){delete[] p;} //析构函数
 friend iter_type operator+(const this_type &a, int n)
 {
  return a.p +n; //返回一个迭代器,可以使用operator*操作
 }
};
由于my_smart_array实现了operator+,因此它支持算术运算,又由于它继承自indexable,所以它还自动获得了operator[]的定义;
my_smart_array<double> ma(new double[10]);
ma[0] = 1.0;  //operatorp[]
*(ma + 1) = 2.0; //指针算术运算
cout<< ma[1] <<endl;

二元操作符:
 operators库提供了使用两个模板类型参数的概念类,用来支持这种用法,例如:less_than_comarable<T, U>.对于不支持模板偏特化的编译器,operator为每个操作符提供额外的两种形式,增加后缀"1"和"2"。如果程序可能在不同的编译器尚编译,为了兼容请使用带后缀的模板:
示例:
class point:
 boost::totally_ordered<point, boost::addable1<point>, boost::addable2<point, int>>
{
 point& operator += (const int &r)
 {
  x += r;
  y += r;
  z += r;
  return *this;
 }
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值