學習C 模板元程式設計(6)

2021-04-12 15:11:24 字數 3946 閱讀 1722

接下來是第六章的一道習題,要求實現乙個

binary_tree_inserter,以使用mpl::copy演算法從其它序列生成一棵二分查詢樹(binary search tree,即滿足以下條件的一種二分樹:左子樹所有元素小於根,右子樹所有元素大於根,且左右子樹全都是二分查詢樹)。習題中給出的測試**如下:

typedef mpl::copy<
mpl::vector_c
, binary_tree_inserter< tree<> >
>::type bst;
//       int_<17>
//       /      /
//    int_<10> int_<25>
//     /    /
// int_<2> int_<11>
boost_static_assert(( mpl::equal<
inorder_view
, mpl::vector_c
>::value ));

使用 mpl::copy演算法依據乙個mpl::vector<>生成二分查詢樹,生成過程中使用乙個inserter依次將mpl::vector<>中的各個元素插入到開始為空的tree<>中,inserter要確保插入後,tree<>保持滿足二分查詢樹的條件。

明顯, inserter要做的就是:從當前tree<>的根開始,如果要插入的元素小於根,則選擇左子樹插入,否則選擇右子樹插入;左右子樹的插入方法與上同,重複以上步驟。

參照書中給出的關於

inserter的例子,

binary_tree_inserter

應該是這樣的:

template
struct push_bst;
template
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
struct tree
;

空的樹既可以直接用

none表示,也可以表示為tree,所以push_bst的第一種情況可以寫為:

template
struct push_bst
: t
;
template
struct push_bst, t>
: tree
;

push_bst的第三種情況(插入到一棵真正的

tree中)寫為:

template
struct push_bst, t>
: mpl::eval_if<
typename mpl::less::type,
tree::type, rc>,
tree::type>
>
;

先判斷插入的元素

t是否小於被插入樹的根,是則將t插入到左子樹後形成新的樹,否則將t插入右子樹後形成新的樹。

最後是 push_bst的第二種情況(插入到只有乙個元素的樹中,且該樹使用該元素直接表示),這也是push_bst的主模板,**如下:

template
struct push_bst
: mpl::eval_if<
typename mpl::less::type,
tree< s, t >,
tree< s, none, t >
>
;

**與前一種情況相似,只不過這次不是用

tree<>來表示樹,而是直接以元素本身表示。

其實,第

二、三種情況也可以合併起來寫,不過就需要另外實現幾個輔助類,分別用於取出二分樹的根、左子樹和右子樹。如果給出的是普通的樹,取出這幾樣東西都很容易(因為我們已經在

tree<>的定義裡typedef了這幾樣東西);但是如果給出的是退化的表示方法(即以元素本身來表示只含單個元素的樹)的話,就必須使用模板偏特化來實現了:

template
struct root
;
template
struct root< tree>
;
template
struct left_child
;
template
struct left_child< tree>
;
template
struct right_child
;
template
struct right_child< tree>
;

有了以上輔助類,就可以將

push_bst的後兩種情況合併為一種寫法:

template
struct push_bst
: mpl::eval_if<
typename mpl::less::type>::type,
tree<
typename root::type,
typename push_bst::type, t>::type,
typename right_child::type
>,
tree<
typename root::type,
typename left_child::type,
typename push_bst::type, t>::type
>
>
;

當然,另兩個

push_bst的特化版本(push_bst和push_bst, t>)還得保留。不過,比較這兩種寫法,後一種寫法雖然減少了push_bst的特化版本,但是引入了多個輔助類,如果這些輔助類沒有其它用途的話,我覺得還是前一種寫法更簡練些。

template <>
struct inorder_view: mpl::vector<>
;

照例,最後是測試用的**:

int main()

這次的

學習C 模板元程式設計(5)

這兩周學習了 c tmp 第 五 六章,是關於tmp的序列 容器 迭代器和演算法。做了不少習題,其中最有意思的 也是花了我最多時間的 習題是用tmp實現二分查詢樹 binary search tree 從第五章的一道關於二分樹的習題開始。題目給出乙個編譯期的二分樹資料結構,例如 typedef tr...

C 模板元程式設計

原理 模板元程式由編譯器在編譯期解釋執行,利用模板特化機制實現編譯期條件選擇結構,利用遞迴模板實現編譯期迴圈結構。模板元程式設計 metaprogramming 意思是,程式設計系統將會執行我們所寫的 來生成新的 而這些新 才真正實現了我們所期望的功能。元程式設計最大的特點在於 某些使用者自定義的計...

C 模板元程式設計

昨天wl發給我一段我覺得很 奇怪 的c 當時沒看太懂,後來問了才知道是叫做模板元程式設計。template struct binary template specialization struct binary 0 terminates recursion 覺得很新奇,於是乎索要了一本電子書,名為 ...