用户操作
[即时聊天] [发私信] [加为好友]
alai04ID:alai04
94438次访问,排名1046,好友0人,关注者2人。
alai04的文章
原创 29 篇
翻译 52 篇
转载 0 篇
评论 79 篇
alai04的公告
EMAIL: alai04@gmail.com

MSN: alai04@hotmail.com

Google 网上论坛
boost_doc_translation
访问此论坛

最近评论
egmkang:对你们辛苦劳动致敬!!!
egmkang:对你们辛苦劳动致敬!!!
gzlyb:谢谢达达的辛勤劳作!
yshuise:向你们致敬,你们做的事勘称伟大!!
cs2213:cs2213@gmail.com
算我一个
文章分类
    收藏
      相册
      文章图片
      C++
      boost文档翻译项目
      C++的罗浮宫
      C类语言讨论与研究圈
      STL中文站(RSS)
      艺术编程
      存档
      软件项目交易
      订阅我的博客
      XML聚合  FeedSky
      订阅到鲜果
      订阅到Google
      订阅到抓虾
      订阅到BlogLines
      订阅到Yahoo
      订阅到GouGou
      订阅到飞鸽
      订阅到Rojo
      订阅到newsgator
      订阅到netvibes

      原创 学习C++模板元编程(6)收藏

      新一篇: 学习C++模板元编程(7) | 旧一篇: 学习C++模板元编程(5)

       
      接下来是第六章的一道习题,要求实现一个binary_tree_inserter,以使用mpl::copy算法从其它序列生成一棵二分查找树(Binary Search Tree,即满足以下条件的一种二分树:左子树所有元素小于根,右子树所有元素大于根,且左右子树全都是二分查找树)。习题中给出的测试代码如下:
      typedef mpl::copy<
            mpl::vector_c<int,17,25,10,2,11>
          , binary_tree_inserter< tree<> >
          >::type bst;
       
      //       int_<17>
      //       /      \
      //    int_<10> int_<25>
      //     /    \
      // int_<2> int_<11>
      BOOST_STATIC_ASSERT(( mpl::equal<
            inorder_view<bst>
          , mpl::vector_c<int,2,10,11,17,25>
          >::value ));
       
      使用mpl::copy算法依据一个mpl::vector<>生成二分查找树,生成过程中使用一个inserter依次将mpl::vector<>中的各个元素插入到开始为空的tree<>中,inserter要确保插入后,tree<>保持满足二分查找树的条件。
      明显,inserter要做的就是:从当前tree<>的根开始,如果要插入的元素小于根,则选择左子树插入,否则选择右子树插入;左右子树的插入方法与上同,重复以上步骤。
      参照书中给出的关于inserter的例子,binary_tree_inserter应该是这样的:
      template <class S, class T>
      struct push_bst;
       
      template <class S>
      struct binary_tree_inserter
          : mpl::inserter<
              S,
              push_bst<_, _>
          >
      {
      };
       
      其中有一个push_bst是辅助类,它执行实际的插入算法。binary_tree_inserter基于push_bst实现。留意binary_tree_inserter定义中的push_bst<_, _>,使用了mpl的占位符(placeholder),占位符的确是一个非常有意思,也非常有用的工具。它可以很方便地将mpl::copy算法在调用binary_tree_inserter时传入的参数,转送到push_bst,不需要你显式地定义出来,大大简化了我们编写MPL程序的工作。
      接着看看push_bst的实现。push_pst的实现分为三种情况:插入到空的树中、插入到只有一个元素的树中、插入非平凡的树中。为了表示空的树,还要定义一个none类来表示空的元素。根据这些想法,修改tree的定义如下:
      struct none {};
       
      template <class R = none, class LC = none, class RC = none>
      struct tree
      {
          typedef tree type;
          typedef R root;
          typedef LC left;
          typedef RC right;
      };
       
      空的树既可以直接用none表示,也可以表示为tree<none, none, none>,所以push_bst的第一种情况可以写为:
      template <class T>
      struct push_bst<none, T>
          : T
      {
      };
       
      template <class T>
      struct push_bst<tree<>, T>
          : tree<T>
      {
      };
       
      push_bst的第三种情况(插入到一棵真正的tree中)写为:
      template <class R, class LC, class RC, class T>
      struct push_bst<tree<R, LC, RC>, T>
          : mpl::eval_if<
              typename mpl::less<T, R>::type,
              tree<R, typename push_bst<LC, T>::type, RC>,
              tree<R, LC, typename push_bst<RC, T>::type>
          >
      {
      };
       
      先判断插入的元素T是否小于被插入树的根,是则将T插入到左子树后形成新的树,否则将T插入右子树后形成新的树。
      最后是push_bst的第二种情况(插入到只有一个元素的树中,且该树使用该元素直接表示),这也是push_bst的主模板,代码如下:
      template <class S, class T>
      struct push_bst
          : mpl::eval_if<
              typename mpl::less<T, S>::type,
              tree< S, T >,
              tree< S, none, T >
          >
      {
      };
       
      代码与前一种情况相似,只不过这次不是用tree<>来表示树,而是直接以元素本身表示。
      其实,第二、三种情况也可以合并起来写,不过就需要另外实现几个辅助类,分别用于取出二分树的根、左子树和右子树。如果给出的是普通的树,取出这几样东西都很容易(因为我们已经在 tree<>的定义里typedef了这几样东西);但是如果给出的是退化的表示方法(即以元素本身来表示只含单个元素的树)的话,就必须使用模板偏特化来实现了:
      template <class T>
      struct root
      {
          typedef T type;
      };
       
      template <class R, class LC, class RC>
      struct root< tree<R, LC, RC> >
      {
          typedef R type;
      };
       
      template <class T>
      struct left_child
      {
         typedef none type;
      };
       
      template <class R, class LC, class RC>
      struct left_child< tree<R, LC, RC> >
      {
          typedef LC type;
      };
       
      template <class T>
      struct right_child
      {
          typedef none type;
      };
       
      template <class R, class LC, class RC>
      struct right_child< tree<R, LC, RC> >
      {
          typedef RC type;
      };
       
      有了以上辅助类,就可以将push_bst的后两种情况合并为一种写法:
      template <class S, class T>
      struct push_bst
          : mpl::eval_if<
              typename mpl::less<T, typename root<S>::type>::type,
              tree< 
                  typename root<S>::type, 
                  typename push_bst<typename left_child<S>::type, T>::type, 
                  typename right_child<S>::type 
              >,
              tree< 
                  typename root<S>::type, 
                  typename left_child<S>::type,
                  typename push_bst<typename right_child<S>::type, T>::type
              >
          >
      {
      };
       
      当然,另两个push_bst的特化版本(push_bst<none, T>和push_bst<tree<>, T>)还得保留。不过,比较这两种写法,后一种写法虽然减少了push_bst的特化版本,但是引入了多个辅助类,如果这些辅助类没有其它用途的话,我觉得还是前一种写法更简练些。
      在进入到最后的测试代码之前,还要稍微修改一下上一篇给出的inorder_view,这是因为这次我们加入了一个none,而上一篇给出的inorder_view没有考虑none的情况。改动其实很少,增加一个针对none的特化版本就行了:
      template <>
      struct inorder_view<none> : mpl::vector<>
      {
      };
       
      照例,最后是测试用的代码:
      int main()
      {
          typedef mpl::copy<
                mpl::vector_c<int,17,25,10,2,11>
              , binary_tree_inserter< tree<> >
              >::type bst;
       
          BOOST_STATIC_ASSERT(( mpl::equal<
                inorder_view<bst>::type
              , mpl::vector_c<int,2,10,11,17,25>
              >::value ));
          
          return 0;
      }
       
      这次的inserter实现比上一次的xxxorder_view相比稍微复杂一些,但也不太难,关键是要理解清楚mpl中的inserter的原理,剩下就都好办了。下一篇将会实现一个完整的编译期Binary Tree,包括了一整套的begin、end、iterator、deref、next、prior等等,然后是在此基础上实现的binary_tree_search算法。
       
       

      发表于 @ 2006年12月22日 16:00:00|评论(loading...)|编辑

      新一篇: 学习C++模板元编程(7) | 旧一篇: 学习C++模板元编程(5)

      评论:没有评论。

      发表评论  


      当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
      Csdn Blog version 3.1a
      Copyright © alai04