自動生成關聯運算符
自定義運算符是C++的一個特色。它可以使用很多操作變得直觀,符合一般的思維方式:
例如,在大多數語言中,對於int這樣的內建類型(primary type)變量a,b,一個運算過程可以寫成:a + b / a – 300,這與數學運算表達式完全一樣。但對於非內建類型,比如Complex就不一定了。比如在Java中,它只能寫成a.add(b.div(a).sub(300)),這就很難看了。而C++中可以通過自定義運算符實現與int類似的運算表達式。
運算符的實現有一個重要的原則:不改變運算符的原意。不應該把“+”號重載成減法運算,也不應把“&&”定義爲乘方,雖然這些重定義在語法上合法。這一原則的一個引申概念就是有關聯的運算符其間的關係不應變化。“+=”和“+”就是一對關聯運算,”<”,”>”,”<=”和”>=”也是一組相關聯的運算。其關聯關係是這樣的:
a = a + b 等價於 a += b
有a < b,也應有 b > a, b>= a, a<=b
關聯運算符應一起實現,爲了保證其相關性不變,在一組關聯運算符中只實現一個基本運算符,其它運算符都使用這個基本運算符實現。例如加法運算以+=爲基本運算,而+調用+=運算符來實現。
class A
{
A& operator+=(A const& a);
};
A operator+(A const& a, A const& b)
{
A result = a;
result += b;
return result;
}
關係運算符更是有一套模式化的實現方法。如果A定義了“<“號,則在STL中爲它定義瞭如下模板。
template <class _Tp>
inline bool _STLP_CALL operator>(const _Tp& __x, const _Tp& __y) {
return __y < __x;
}
template <class _Tp>
inline bool _STLP_CALL operator<=(const _Tp& __x, const _Tp& __y) {
return !(__y < __x);
}
template <class _Tp>
inline bool _STLP_CALL operator>=(const _Tp& __x, const _Tp& __y) {
return !(__x < __y);
}
它們被定義在std::rel_ops命名空間中,要使用它們,需要在類中聲明using namespace std::rel_ops。
這可以算是最基本的一個關聯運算符生成器了,可惜它太少了一點,也不夠靈活。不過在boost庫中這個強大的功能被補全了,這就是boost::operators。
operator主要通過繼承和友元來爲類型提供運算符定義。
用法1通過繼承:
class A : boost:: less_than_comparable<A>
{
friend bool operator<(A const&a, A const& b);
};
用法2通過模板友元:
class A
{
friend bool operator<(A const&a, A const& b);
};
template boost:: less_than_comparable<A>; //顯式實例化模板。
boost:: less_than_comparable模板類提供了以下一組友元:
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !(y < x); }
friend bool operator>=(const T& x, const T& y) { return !(x < y); }
它們都依賴於A定義的operator<運算符。
Boost不只提供只對於當前類型的運算符,還提供類型之間的運算符,如下代碼。
用法1通過繼承:
class A : boost:: less_than_comparable<A,B>
{
friend bool operator<(A const&a, B const& b);
friend bool operator>(A const&a, B const& b);
};
用法2通過模板友元:
class A
{
friend bool operator<(A const&a, B const& b);
friend bool operator>(A const&a, B const& b);
};
template boost:: less_than_comparable<A, B>; //顯式實例化模板。
boost:: less_than_comparable<A,B>模板類提供了以下一組友元:
bool operator<=(const T&, const U&)
bool operator>=(const T&, const U&)
bool operator>(const U&, const T&)
bool operator<(const U&, const T&)
bool operator<=(const U&, const T&)
bool operator>=(const U&, const T&)
以下是一張boost提供的模板,模板提供的運算符和模板所依賴的運算符的對應表。
T
: primary operand type U
: alternate operand type t
, t1
: values of type T u
: value of type U
模板 |
提供的操作符 |
所依賴的運算符 |
less_than_comparable<T> less_than_comparable1<T> |
bool operator>(const T&, const T&) |
t < t1. |
less_than_comparable<T, U> |
bool operator<=(const T&, const U&) |
t < u. t > u. |
equality_comparable<T> |
bool operator!=(const T&, const T&) |
t == t1. |
equality_comparable<T, U> |
bool operator==(const U&, const T&) |
t == u. |
addable<T> |
T operator+(const T&, const T&) |
T temp(t); temp += t1. |
addable<T, U> |
T operator+(const T&, const U&) |
T temp(t); temp += u. |
subtractable<T> |
T operator-(const T&, const T&) |
T temp(t); temp -= t1. |
subtractable<T, U> |
T operator-(const T&, const U&) |
T temp(t); temp -= u. |
subtractable2_left<T, U> |
T operator-(const U&, const T&) |
T temp(u); temp -= t. |
multipliable<T> |
T operator*(const T&, const T&) |
T temp(t); temp *= t1. |
multipliable<T, U> |
T operator*(const T&, const U&) |
T temp(t); temp *= u. |
dividable<T> |
T operator/(const T&, const T&) |
T temp(t); temp /= t1. |
dividable<T, U> |
T operator/(const T&, const U&) |
T temp(t); temp /= u. |
dividable2_left<T, U> |
T operator/(const U&, const T&) |
T temp(u); temp /= t. |
modable<T> |
T operator%(const T&, const T&) |
T temp(t); temp %= t1. |
modable<T, U> |
T operator%(const T&, const U&) |
T temp(t); temp %= u. |
modable2_left<T, U> |
T operator%(const U&, const T&) |
T temp(u); temp %= t. |
orable<T> |
T operator|(const T&, const T&) |
T temp(t); temp |= t1. |
orable<T, U> |
T operator|(const T&, const U&) |
T temp(t); temp |= u. |
andable<T> |
T operator&(const T&, const T&) |
T temp(t); temp &= t1. |
andable<T, U> |
T operator&(const T&, const U&) |
T temp(t); temp &= u. |
xorable<T> |
T operator^(const T&, const T&) |
T temp(t); temp ^= t1. |
xorable<T, U> |
T operator^(const T&, const U&) |
T temp(t); temp ^= u. |
incrementable<T> |
T operator++(T&, int) |
T temp(t); ++t |
decrementable<T> |
T operator--(T&, int) |
T temp(t); --t; |
left_shiftable<T> |
T operator<<(const T&, const T&) |
T temp(t); temp <<= t1. |
left_shiftable<T, U> |
T operator<<(const T&, const U&) |
T temp(t); temp <<= u. |
right_shiftable<T> |
T operator>>(const T&, const T&) |
T temp(t); temp >>= t1. |
right_shiftable<T, U> |
T operator>>(const T&, const U&) |
T temp(t); temp >>= u. |
equivalent<T> |
bool operator==(const T&, const T&) |
t < t1. |
equivalent<T, U> |
bool operator==(const T&, const U&) |
t < u. t > u. |
partially_ordered<T> |
bool operator>(const T&, const T&) |
t < t1. t == t1. |
partially_ordered<T, U> |
bool operator<=(const T&, const U&) |
t < u. t > u. t == u. |
對於同一個類要實現多組運算符,operators採用鏈式繼承的方式,例如如果需要同時定義小於和等於符號。可以這樣定義:
class A : boost:: less_than_comparable<A, equality_comparable<A> >
{
friend bool operator<(A const&a, A const& b);
friend bool operator==(A const&a, A const& b);
};
如果是定義類型間的小於和等於,則是這樣:
class A : boost:: less_than_comparable<A,B,equality_comparable<A,B> >
{
friend bool operator<(A const&a, B const& b);
friend bool operator>(A const&a, B const& b);
friend bool operator==(A const&a, B const& b);
};
boost預先定義了一些組合運算模板,也可以直接使用它們,例如上面的類也可以定義爲:
class A : totally_ordered<T>
{
friend bool operator<(A const&a, A const& b);
friend bool operator==(A const&a, A const& b);
};
以下是一個稱爲聯合運算的組合運算模板的組成表:
Template |
Component Operator Templates |
totally_ordered<T> |
· less_than_comparable<T> |
totally_ordered<T, U> |
|
additive<T> |
|
additive<T, U> |
|
multiplicative<T> |
|
multiplicative<T, U> |
|
integer_multiplicative<T> |
|
integer_multiplicative<T, U> |
|
arithmetic<T> |
|
arithmetic<T, U> |
|
integer_arithmetic<T> |
|
integer_arithmetic<T, U> |
|
bitwise<T> |
|
bitwise<T, U> |
|
unit_steppable<T> |
|
shiftable<T> |
|
shiftable<T, U> |
|
ring_operators<T> |
|
ring_operators<T, U> |
|
ordered_ring_operators<T> |
|
ordered_ring_operators<T, U> |
|
field_operators<T> |
|
field_operators<T, U> |
|
ordered_field_operators<T> |
|
ordered_field_operators<T, U> |
|
euclidian_ring_operators<T> |
|
euclidian_ring_operators<T, U> |
|
ordered_euclidian_ring_operators<T> |
|
ordered_euclidian_ring_operators<T, U> |
· euclidian_ring_operators<T, U> · totally_ordered<T, U> |
與其它boost庫一樣,operators要求支持C++98標準的編譯器,現在完全支持的編譯器有VC7.1,GCC3.3,EGD 2.5以上。通過一定的方式支持GCC2.95和VC6 sp3以上。
對於完全支持的編譯器,推薦使用operatorable<T>和operatorable<T, U>模板。對於不完全支持的編譯器,可以使用operatorable1<T>和operatorable2<T,U>這兩個接口。