Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Extending return type deduction system(擴展返回類型推演系統)

本節,我們講解如何擴展返回類型推演系統以包括用戶定義操作符。很多情況下這沒有必要,因為 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, 或二元情況下的 AB,代表操作符調用的參數類型。兩套模板,plain_return_type_nreturn_type_nn 為 1 或 2)的區別在於將參數類型呈現給它們的方法不同。對於前者,參數類型總是以非引用類型提供,而且沒有 const 或 volatile 修飾符。這將使特化比較簡單,而且通常對於每一個用戶定義操作符,或操作符組只需要一個特化就足夠了。另一方面,如果一個特定的操作符針對同樣的參數類型 的不同 cv 修飾進行了重載,而且這些重載版本的返回類型不同,就需要一個更細緻的控制機制。因此,對於後者,參數類型帶有 cv 修飾符,而且是非引用類型為好。不利方面在於,對於上面描述的這種操作符的一套重載,有人最多可能會需要 16 個 return_type_2 的特化。

假設用戶擁有下面的操作符針對某些用戶定義類型 X, YZ 的重載:

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,為了簡單起見,在下面的示例中我們 沒有表明名字空間定義。

除了為一組操作符提供一個特化外,有時在個別操作符的層次上提供特化可能更好。比如說,我們為參數類型 XY 增加一個新的算術操作符:

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

PrevUpHomeNext