posts - 18,  comments - 104,  trackbacks - 0


今天闲来无事,实现了一个简版的boost::tuple作为练习,贴出来,仅供参考。

为了看起来清晰,tuple只支持3个参数,只要在注释为A的地方继续增加模板参数和构造函数的参数个数,就可以增加tuple元素的个数。
没有type_trait,只为清晰,可读。加了一点注释,其中“递归”二字有时候说的不恰当,因为看似一个函数,实则不是一个函数。
仔细读代码吧。
轻拍

  1 // 空类型,作为type_list的结束标记。
  2 
  3 struct null_type
  4 {
  5     // 在tuple链的最尾端,构造一个null_type,对应type_list尾端的null_type.
  6     null_type()
  7     {}
  8 
  9     // 这个构造函数完全是为了简化cons的构造函数,其实是个“递归”结束条件。  A
 10     template <class T1, class T2, class T3, class T4>
 11     null_type(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
 12     {}
 13 };
 14 
 15 // type_list + data_list声明。
 16 template <typename HH, typename TT>
 17 struct cons;
 18 
 19 // 用于在type_list中找到第N个类型,下标从1开始。
 20 template <int N, typename _T>
 21 struct element
 22 {
 23     typedef typename element<N-1, typename _T::tail_type>::type type;
 24 };
 25 
 26 // 所以特化为1,要是想从0开始,就特化0.
 27 template <typename _T>
 28 struct element<1, _T>
 29 {
 30     typedef typename _T::head_type type;
 31 };
 32 
 33 // 得到第N个类型对于的数据,注意是递归调用,对于不同的get_class<N>::get, get_class<N-1>::get  一直到 get_class<1>::get。
 34 template <int N>
 35 struct get_class
 36 {
 37     template <typename RET, typename HH, typename TT>
 38     static RET get(cons<HH, TT>& c)
 39     {
 40         return get_class<N-1>::get<RET>(c.tail);
 41     }
 42 };
 43 
 44 // 下标依然从1开始。
 45 template <>
 46 struct get_class<1>
 47 {
 48     template <typename RET, typename HH, typename TT>
 49     static RET get(cons<HH, TT>& c)
 50     {
 51         return c.head;
 52     }
 53 };
 54 
 55 // 继续包装,为了方便使用,得到第N个类型对应的数据。
 56 template <int N, typename HH, typename TT>
 57 typename element<N, cons<HH, TT> >::type&
 58 get(cons<HH, TT>& c)
 59 {
 60     return get_class<N>::get<element<N, cons<HH, TT> >::type&>(c);
 61 }
 62 
 63 // type_list + data_list 的定义。
 64 template <typename HH, typename TT>
 65 struct cons
 66 {
 67     typedef HH head_type;
 68     typedef TT tail_type;
 69 
 70     head_type head;
 71     tail_type tail;
 72 
 73     // 构造函数,注意递归构造,递归结束条件是null_type的构造函数。  A
 74     template <class T1, class T2, class T3>
 75     cons( T1& t1, T2& t2, T3& t3, null_type)
 76         : head (t1),
 77         tail (t2, t3, null_type(), null_type())
 78     {}
 79 
 80     // 包装的get方法,其实质还是调用全局的get,参数为*this。
 81     template <int N>
 82     typename element<N, cons<HH, TT> >::type
 83         get()
 84     {
 85         return ::get<N>(*this);
 86     }
 87 };
 88 
 89 // 构造type_list.主要是为了将序列式的模板参数转化成type_list的样子。  A
 90 template <class T0, class T1, class T2>
 91 struct map_tuple_to_cons
 92 {
 93     typedef cons<T0, typename map_tuple_to_cons<T1, T2, null_type>::type> type;
 94 };
 95 // 停止条件。
 96 template <>
 97 struct map_tuple_to_cons<null_type, null_type, null_type>
 98 {
 99     typedef null_type type;
100 };
101 
102 // 包装成tuple,其实就是一个type_list + data_list.                   A
103 template <class T0, class T1 = null_type, class T2 = null_type>    
104 struct tuple : public map_tuple_to_cons<T0, T1, T2>::type
105 {
106     typedef typename map_tuple_to_cons<T0, T1, T2>::type base;
107 
108     tuple(const T0& t0) : base(t0, null_type(), null_type(), null_type())
109     {
110     };
111 
112     tuple(const T0& t0, const T1& t1) : base(t0, t1, null_type(),
113         null_type())
114     {
115     };
116 
117     tuple(const T0& t0, const T1& t1, const T1& t2) : base(t0, t1, t2,
118         null_type())
119     {
120     };
121 };
122 
123 // test.
124 int main()
125 {
126     tuple<int> x(3);
127     tuple<doubleint> y(5.42);
128 
129     int x1 = get<1>(x);
130     double y1 = get<1>(y);
131     int y2 = get<2>(y);
132 
133     x1 = x.get<1>();
134     y1 = y.get<1>();
135     y2 = y.get<2>();
136 }
posted on 2009-02-24 22:07 尹东斐 阅读(1711) 评论(4)  编辑 收藏 引用

FeedBack:
# re: 实做练习 boost::tuple, 仅供学习。
2009-02-25 16:46 | 路人
效率很低啊,访问一个节点要付出N次get递归函数调用的消耗。  回复  更多评论
  
# re: 实做练习 boost::tuple, 仅供学习。
2009-02-25 20:14 | yindf
@路人

效率是低,但是按照boost::tuple的解释是,如果编译器优化好的话,这些函数将都是尾递归,相当与循环的说。  回复  更多评论
  
# re: 实做练习 boost::tuple, 仅供学习。
2009-02-25 20:44 | 路人
还不如用“穷举"的方法,搞成tuple1<typename T1>,tuple2<typename T1,typename T2>.....,直接存取地址效率高很多。  回复  更多评论
  
# re: 实做练习 boost::tuple, 仅供学习。
2009-02-25 23:29 | yindf
@路人

问题是C++目前不支持重载模板参数,要是可以,你的方法很赞。
每个tuple后面加个数字实在不咋好看呀。

而且要是我想知道tuple3第3个元素的类型,怎么办?  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2009年5月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

常用链接

留言簿(4)

随笔档案

文章分类

文章档案

相册

好友博客

搜索

  •  

最新评论

阅读排行榜

评论排行榜