![]() |
Home | Libraries | People | FAQ | More |
本節,我們講解如何擴展返回類型推演系統以包括用戶定義操作符。很多情況下這沒有必要,因為 BLL
定義了操作符的缺省返回類型。例如,所有比較操作符的缺省返回類型是 bool,
那麼,只要用戶定義的比較操作符具有一個 bool 類型的返回值,就不需要為返回類型推演類提供新的特化。不過,有時這卻必不可少。
可重載用戶定義操作符既有一元的也有二元的。對每一個數量,有兩個定義不同操作符的返回類型的特徵模板。因此,返回類型系統可以通過提
供對這些模板的更多特化來進行擴展。用於一元函數的模板是 plain_return_type_1<Action,
A> 和 return_type_1<Action,
A>,用於二元函數的模板是 plain_return_type_2<Action,
A, B> 和 return_type_2<Action,
A, B>。
傳給這些模板的第一個參數 (Action)
是指定操作符的 action
類,具有相似返回值規則的操作符組織到 action
groups(action 組)中,而且只有 action 類和 action
組一起可以明確定義操作符。例如,action 類型 arithmetic_action<plus_action>
代表 operator+。各種 action
類型的完整列表參見 Table 11.2 「Action types」。
後面的參數,一元情況下的 A,
或二元情況下的 A 和 B,代表操作符調用的參數類型。兩套模板,plain_return_type_
和 nreturn_type_(nn
為 1 或 2)的區別在於將參數類型呈現給它們的方法不同。對於前者,參數類型總是以非引用類型提供,而且沒有 const 或 volatile
修飾符。這將使特化比較簡單,而且通常對於每一個用戶定義操作符,或操作符組只需要一個特化就足夠了。另一方面,如果一個特定的操作符針對同樣的參數類型
的不同 cv 修飾進行了重載,而且這些重載版本的返回類型不同,就需要一個更細緻的控制機制。因此,對於後者,參數類型帶有 cv
修飾符,而且是非引用類型為好。不利方面在於,對於上面描述的這種操作符的一套重載,有人最多可能會需要 16 個 return_type_2 的特化。
假設用戶擁有下面的操作符針對某些用戶定義類型 X,
Y 和 Z 的重載:
Z operator+(const X&, const Y&);
Z operator-(const X&, const Y&);
現在,要增加一種特化情形,這種情形中左側參數為類型 X,
右側參數為類型 Y,所有這樣的二元算術操作符的
返回類型都是 Z:
namespace boost {
namespace lambda {
template<class Act>
struct plain_return_type_2<arithmetic_action<Act>, X, Y> {
typedef Z type;
};
}
}
有了這個特化定義,BLL 就可以正確推演上面兩個操作符的返回類型。注意,特化必須和原來的模板在同樣的名字空間中,::boost::lambda,為了簡單起見,在下面的示例中我們
沒有表明名字空間定義。
除了為一組操作符提供一個特化外,有時在個別操作符的層次上提供特化可能更好。比如說,我們為參數類型 X 和 Y
增加一個新的算術操作符:
X operator*(const X&, const Y&);
我們先前的規則是針對返回類型為 Z
的所有算術操作符特化的,這裡顯然不是這種情況。因此,我們為乘法操作符提供了一個新的規則:
template<>
struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> {
typedef X type;
};
特化可以定義從參數類型到返回類型的任意映射。假設我們有某一數學 vector 類型,它的元素類型被模板化:
template <class T> class my_vector;
假設在任何兩個 my_vector
實例之間,只要它們的元素之間定義了加法操作符,就要在這兩個 my_vector
實例之間定義加法操作符。而且,存儲結果的 my_vector
的元素類型和元素之間加法的結果類型相同。例如,my_vector<int>
和 my_vector<double>
相加的結果存儲在 my_vector<double>
中。BLL 中有特徵類用來執行整型,浮點數和複雜類之間的隱式內建類型轉換和標準類型轉換。使用 BLL 工具,上面描述的加法操作符可以定義為:
template<class A, class B>
my_vector<typename return_type_2<arithmetic_action<plus_action>, A, B>::type>
operator+(const my_vector<A>& a, const my_vector<B>& b)
{
typedef typename
return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
return my_vector<res_type>();
}
為了讓 BLL 能夠正確推演 my_vector
的類型,我們可以定義:
template<class A, class B>
class plain_return_type_2<arithmetic_action<plus_action>,
my_vector<A>, my_vector<B> > {
typedef typename
return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
public:
typedef my_vector<res_type> type;
};
注意,我們復用了對 BLL 的 return_type_2
模板的已有的特化,它需要參數類型為引用。
Table 11.2 Action types
+ |
arithmetic_action<plus_action> |
- |
arithmetic_action<minus_action> |
* |
arithmetic_action<multiply_action> |
/ |
arithmetic_action<divide_action> |
% |
arithmetic_action<remainder_action> |
+ |
unary_arithmetic_action<plus_action> |
- |
unary_arithmetic_action<minus_action> |
& |
bitwise_action<and_action> |
| |
bitwise_action<or_action> |
~ |
bitwise_action<not_action> |
^ |
bitwise_action<xor_action> |
<< |
bitwise_action<leftshift_action_no_stream> |
>> |
bitwise_action<rightshift_action_no_stream> |
&& |
logical_action<and_action> |
|| |
logical_action<or_action> |
! |
logical_action<not_action> |
< |
relational_action<less_action> |
> |
relational_action<greater_action> |
<= |
relational_action<lessorequal_action> |
>= |
relational_action<greaterorequal_action> |
== |
relational_action<equal_action> |
!= |
relational_action<notequal_action> |
+= |
arithmetic_assignment_action<plus_action> |
-= |
arithmetic_assignment_action<minus_action> |
*= |
arithmetic_assignment_action<multiply_action> |
/= |
arithmetic_assignment_action<divide_action> |
%= |
arithmetic_assignment_action<remainder_action> |
&= |
bitwise_assignment_action<and_action> |
=| |
bitwise_assignment_action<or_action> |
^= |
bitwise_assignment_action<xor_action> |
<<= |
bitwise_assignment_action<leftshift_action> |
>>= |
bitwise_assignment_action<rightshift_action> |
++ |
pre_increment_decrement_action<increment_action> |
-- |
pre_increment_decrement_action<decrement_action> |
++ |
post_increment_decrement_action<increment_action> |
-- |
post_increment_decrement_action<decrement_action> |
& |
other_action<address_of_action> |
* |
other_action<contents_of_action> |
, |
other_action<comma_action> |
->* |
other_action<member_pointer_action> |
| Copyright 1999-2004 Jaakko Jrvi, Gary Powell |