学习C++模板元编程(5)

 
这两周学习了《 C++ TMP》第五、六章,是关于TMP的序列(容器)、迭代器和算法。做了不少习题,其中最有意思的(也是花了我最多时间的)习题是用TMP实现二分查找树(Binary Search Tree)。
从第五章的一道关于二分树的习题开始。题目给出一个编译期的二分树数据结构,例如:
   typedef tree<                  //     double
         double                   //     /   /
       , tree<void*,int,long>     //   void* char
       , char                     //   / /
       > tree_seq;                // int long
要求实现对该二分树的前序、中序、后序遍历,即满足:
   BOOST_STATIC_ASSERT(( mpl::equal<
         preorder_view<tree_seq>
       , mpl::vector<double,void*,int,long,char>
       , boost::is_same<_1,_2>
       >::value ));
 
   BOOST_STATIC_ASSERT(( mpl::equal<
         inorder_view<tree_seq>
       , mpl::vector<int,void*,long,double,char>
       , boost::is_same<_1,_2>
       >::value ));
 
   BOOST_STATIC_ASSERT(( mpl::equal<
         postorder_view<tree_seq>
       , mpl::vector<int,long,void*,char,double>
       , boost::is_same<_1,_2>
       >::value ));
其实这三种遍历是很相似的,实现了其中一个,另两个就可以照着写了。所以我们先从 preorder_view开始着手。
当然,最开始还是要先定义 tree,如下:
template <class R, class LC, class RC>
struct tree
{
    typedef tree type;
    typedef R root;
    typedef LC left;
    typedef RC right;
};
 
其中 type的定义是为了满足boost::mpl的惯例,其余三个定义显而易见,是为了可以方便地取出tree类的根、左子树和右子树。接着,我们来看看如何实现preorder_view。从题目给出的测试代码可知,preorder_view的调用结果应该是类似于mpl::vector<>的一个序列,里面是按前序的方式对tree进行遍历所得到的元素。所以,我干脆就用mpl::vector<>来作为preorder_view的调用结果,先写出主模板的初稿:
template <class T>
struct preorder_view : mpl::vector<T>
{
};
 
再针对 tree<>类进行偏特化,如下:
template <class R, class LC, class RC>
struct preorder_view< tree<R, LC, RC> >
{
    typedef mpl::vector<R>s t1;
    typedef typename mpl::insert_range<t1, typename mpl::end<t1>::type,
        typename preorder_view<LC>::type >::type t2;
    typedef typename mpl::insert_range<t2, typename mpl::end<t2>::type, 
        typename preorder_view<RC>::type >::type type;
};
 
这段代码是按照前序的方式来实现,即先访问根元素,然后以前序方式访问左子树,再以前序方式访问右子树。这个偏特化版本与主模板一道,就可以实现前序遍历了。相似地,我们可以写出 inorder_view和postorder_view,如下:
template <class T>
struct inorder_view : mpl::vector<T>
{
};
 
template <class R, class LC, class RC>
struct inorder_view< tree<R, LC, RC> >
{
    typedef typename inorder_view<LC>::type t1;
    typedef typename mpl::insert_range<t1, typename mpl::end<t1>::type,
        mpl::vector<R> >::type t2;
    typedef typename mpl::insert_range<t2, typename mpl::end<t2>::type, 
        typename inorder_view<RC>::type >::type type;
};
 
template <class T>
struct postorder_view : mpl::vector<T>
{
};
 
template <class R, class LC, class RC>
struct postorder_view< tree<R, LC, RC> >
{
    typedef typename postorder_view<LC>::type t1;
    typedef typename mpl::insert_range<t1, typename mpl::end<t1>::type, 
        typename postorder_view<RC>::type >::type t2;
    typedef typename mpl::insert_range<t2, typename mpl::end<t2>::type,
        mpl::vector<R> >::type type;
};
 
最后是测试代码:
int main()
{
    typedef tree< double, tree<void*,int,long>, char > tree_seq;
 
    BOOST_STATIC_ASSERT(( mpl::equal<
         preorder_view<tree_seq>::type
        , mpl::vector<double,void*,int,long,char>
        >::value ));
    
    BOOST_STATIC_ASSERT(( mpl::equal<
         inorder_view<tree_seq>::type
        , mpl::vector<int,void*,long,double,char>
        >::value ));
    
    BOOST_STATIC_ASSERT(( mpl::equal<
         postorder_view<tree_seq>::type
        , mpl::vector<int,long,void*,char,double>
        >::value ));
    
    return 0;
}
 
应该说,这个开头还是比较容易的,不过后面就有点难度了。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值