先看看boost的實現吧。
1 template<typename _T>
2 struct wapper
3 {};
4 template <typename _T>
5 _T&(* fun1(wapper<_T> t))();
6 true_type fun1(
);
7
8 class true_type{};
9 class false_type
10 {
11 char c[8];
12 };
13
14 template<typename _T>
15 true_type fun2(_T&(*)());
16 false_type fun2(
);
17
18 template<typename _T>
19 struct is_reference
20 {
21 static const bool value = sizeof(fun2(fun1(wapper<_T>()))) == sizeof(false_type);
22 };
就是上面這個樣子,我做了一下簡化,更容易理解。
下面是我的實現版本,最后再解釋。
1 template<typename _T>
2 class is_reference
3 {
4 template<typename _T>
5 struct wapper
6 {};
7
8 class true_type{};
9 class false_type
10 {
11 char c[8];
12 };
13
14 template <typename _T>
15 static _T& fun1(wapper<_T>);
16 static true_type fun1(
);
17
18 template<typename _T>
19 static true_type fun2(_T);
20 static false_type fun2(true_type);
21 public:
22 static const bool value = sizeof(fun2(fun1(wapper<_T>()))) == sizeof(false_type);
23 };
用法如下:
1 bool res1 = is_reference<char>::value; //res1 == false
2 bool res2 = is_reference<char&>::value; //res2 == true
函數參數會自動去掉引用比如:
template<_T> void fun(_T a);
無論任何時候,_T總是非引用類型。
但是不讓函數通過函數參數直接推導模板參數的類型,就給函數參數加一個間接層wapper,
類模板不會自動去掉引用,所以配合函數模板可以保證得到原來的類型。
template<_T> void fun(wapper<_T> a);
這時候,_T 就可能是引用類型了。因為c++不支持引用的引用,當模板函數中要用到引用的引用的時候,模板函數就會推導失敗。
即,只要在函數fun的參數或者返回值里面含有_T&的話,fun就會推導失敗。從而編譯器會選擇 true_type fun(...);
由于參數已經被用于推導模板參數,所以只能在返回類型中含有_T&,從而利用函數重載而區分引用和非引用。
如果直接返回_T&類型,后面必須要定義只接受true_type類型參數的函數進行區分,因為_T&肯定是引用類型,所以后面接受
false_type fun2(true_type)的函數會被選擇。
但是遇到is_reference<true_type>::value怎么辦,我把他們都放到私有域了,永遠不會看到的,搞定。
boost::trait中返回函數指針的解法也OK。因為char永遠不可能成功匹配函數指針。
此方法的關鍵在于編譯器選擇重載函數的先后順序。
而boost::trait中的方法是char永遠不能轉化成一個函數指針,從而選擇不同重載版本。
解釋完畢。
posted on 2009-02-20 21:44
尹東斐 閱讀(2122)
評論(5) 編輯 收藏 引用