先看看boost的實(shí)現(xiàn)吧。
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 };
就是上面這個(gè)樣子,我做了一下簡化,更容易理解。
下面是我的實(shí)現(xiàn)版本,最后再解釋。
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
函數(shù)參數(shù)會(huì)自動(dòng)去掉引用比如:
template<_T> void fun(_T a);
無論任何時(shí)候,_T總是非引用類型。
但是不讓函數(shù)通過函數(shù)參數(shù)直接推導(dǎo)模板參數(shù)的類型,就給函數(shù)參數(shù)加一個(gè)間接層wapper,
類模板不會(huì)自動(dòng)去掉引用,所以配合函數(shù)模板可以保證得到原來的類型。
template<_T> void fun(wapper<_T> a);
這時(shí)候,_T 就可能是引用類型了。因?yàn)閏++不支持引用的引用,當(dāng)模板函數(shù)中要用到引用的引用的時(shí)候,模板函數(shù)就會(huì)推導(dǎo)失敗。
即,只要在函數(shù)fun的參數(shù)或者返回值里面含有_T&的話,fun就會(huì)推導(dǎo)失敗。從而編譯器會(huì)選擇 true_type fun(...);
由于參數(shù)已經(jīng)被用于推導(dǎo)模板參數(shù),所以只能在返回類型中含有_T&,從而利用函數(shù)重載而區(qū)分引用和非引用。
如果直接返回_T&類型,后面必須要定義只接受true_type類型參數(shù)的函數(shù)進(jìn)行區(qū)分,因?yàn)開T&肯定是引用類型,所以后面接受
false_type fun2(true_type)的函數(shù)會(huì)被選擇。
但是遇到is_reference<true_type>::value怎么辦,我把他們都放到私有域了,永遠(yuǎn)不會(huì)看到的,搞定。
boost::trait中返回函數(shù)指針的解法也OK。因?yàn)閏har永遠(yuǎn)不可能成功匹配函數(shù)指針。
此方法的關(guān)鍵在于編譯器選擇重載函數(shù)的先后順序。
而boost::trait中的方法是char永遠(yuǎn)不能轉(zhuǎn)化成一個(gè)函數(shù)指針,從而選擇不同重載版本。
解釋完畢。
posted on 2009-02-20 21:44
尹東斐 閱讀(2130)
評(píng)論(5) 編輯 收藏 引用