先看看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
尹东斐 阅读(2111)
评论(5) 编辑 收藏 引用