boost中operators库提供了一系列的操作符重载自动生成工具类,只需要提供少量操作即可自动重载其他操作符。
我们先来看两段源码:
template <class T, class U, class B = ::boost::detail::empty_base<T> >
struct less_than_comparable2 : B
{
friend bool operator<=(const T& x, const U& y) { return !static_cast<bool>(x > y); }
friend bool operator>=(const T& x, const U& y) { return !static_cast<bool>(x < y); }
friend bool operator>(const U& x, const T& y) { return y < x; }
friend bool operator<(const U& x, const T& y) { return y > x; }
friend bool operator<=(const U& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const U& x, const T& y) { return !static_cast<bool>(y > x); }
};
template <class T, class B = ::boost::detail::empty_base<T> >
struct less_than_comparable1 : B
{
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};
template <class T, class U, class B = ::boost::detail::empty_base<T> >
struct equality_comparable2 : B
{
friend bool operator==(const U& y, const T& x) { return x == y; }
friend bool operator!=(const U& y, const T& x) { return !static_cast<bool>(x == y); }
friend bool operator!=(const T& y, const U& x) { return !static_cast<bool>(y == x); }
};
template <class T, class B = ::boost::detail::empty_base<T> >
struct equality_comparable1 : B
{
friend bool operator!=(const T& x, const T& y) { return !static_cast<bool>(x == y); }
};
less_than_comparable2 与 less_than_comparable1提供比较操作重载,由源码可知两个工具类的重载主要借助operator<操作符实现。
与此类似,quality_comparable2与equality_comparable1提供相等操作的重载,其借助operator==操作符实现。
typename##2系列与typename##1系列不同在于前者提供相异类型的操作符重载。算是一种扩充。
缺省模板参数 empty_base确实是空类,其作用随后再讲。
我们如何使用operator库呢?下面是示例
#include <boost/operators.hpp>
class 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 << " " << y << " " << z; }
friend bool operator<(const point& l, const point& r)//支持less_than_comparable
{
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);
}
}
operator<必须声明为友元,因为在重载工具类中要使用该操作符。
当类继承自boost::equality_comparable并且定义了operator< 其”>”,”<=”,”>==”操作符都已经被自动重载。
编译器如何通过equality_comparable来自动匹配less_than_comparable2 或less_than_comparable1?
源码中有如下系列声明:
BOOST_OPERATOR_TEMPLATE(less_than_comparable)
BOOST_OPERATOR_TEMPLATE(equality_comparable)
...
宏展开如下:
# define BOOST_OPERATOR_TEMPLATE(template_name) \
template <class T \
,class U = T \
,class B = ::boost::detail::empty_base<T> \
,class O = typename is_chained_base<U>::value \
> \
struct template_name : template_name##2<T, U, B> {}; \
\
template<class T, class U, class B> \
struct template_name<T, U, B, ::boost::detail::true_t> \
: template_name##1<T, U> {}; \
\
template <class T, class B> \
struct template_name<T, T, B, ::boost::detail::false_t> \
: template_name##1<T, B> {}; \
\
template<class T, class U, class B, class O> \
struct is_chained_base< ::boost::template_name<T, U, B, O> > { \
typedef ::boost::detail::true_t value; \
}; \
该宏操作声明了多组操作符重载模板,编译时自动匹配对应模板。
接下来我们扩充class point功能:
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 << " " << y << " " << z; }
friend bool operator<(const point& l, const point& r)//支持less_than_comparable
{
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)//支持equality_comparable
{
return l.x == r.x && l.y == r.y && l.z == r.z;
}
}
此时class point已经支持 “<”,”>”,”>=”,”<=”,”==”,”!=”这些操作符。
C++支持多重继承,但是多重继承本身有可能导致钻石继承、优化困难等问题,为此泛型编程有种技术叫做”基类链”来解决多重继承的问题。相当于从一对多的聚集状继承模型转换为了单链式继承模型。子类本身只有一个父类,却拥有上层父类所有特性。
前面我们提到重载模板有个模板参数class B ,通常设置为empty class。他主要用于基类链技术。
如上例中:
class point :boost::less_than_comparable<point>,
boost::equality_comparable<point>
其等价于如下写法:
class point :boost::less_than_comparable<point, boost::equality_comparable<point>>//基类链
boost::equality_comparable取代了 empty_base的位置,避免了多重继承。
//基类链技术使用示例
class empty_class {};
template<typename T = empty_class>
class function_class1: public T
{
public:
void do_something(){}
};
template<typename T = empty_class>
class function_class2: public T
{
public:
void do_anotherthing(){}
};
class your_class : public function_class2<function_class1<>>
{
public:
void your_work_func(){}
};
void test_func()
{
your_class you;
you.do_something();
you.do_anotherthing();
you.your_work_func();
}
其他操作如totally_ordered( 全序概念(比较操作))、additive(可加减操作)等读者可查阅相关资料学习。
部分代码示例来自《Boost程序库完全开发指南:深入C++_准备标准库 第3版》