用模板類和模板函式是c++程式猿必須掌握的技能。然而要充分運用編譯器的推導能力則不簡單。
需求:建立乙個**類, 每一列的型別可以任意指定(編譯期指定),每一行的元素可以任意指定(執行期確定)。列數可變(編譯期指定),行數可變(執行期確定)。
這裡特意強調了編譯期和執行期,就是為了最大程度利用編譯器的推導能力,進行編譯期計算,以達到(接近)最高效率。
so, let『s begin!!
將任務拆解,顯然每列元素可以直接用stl的各種容器完成,這裡暫時放下不表;行元素咋辦呢?
task1: 列數可變,但是在編譯器能確定。
這裡用到了c++11的variadic template
特性。雖然之前也可以支援這種類似的寫法,但是各種巨集很容易把猿猿搞暈。還是新標準來得清爽。
// generic of typelist
template struct typelist{};
// specific of typelist
template <>
struct typelist<>{};
// partial specific of typelist
template struct typelist: public typelist
};int main()
// output:
// type: d
// type: c
// type: i
通過(編譯期)遞迴形式達到型別和數量都可變的目的。
task2: 如何獲得第i列的型別, 好為get函式做準備?
// traits: typeofindextemplate struct typeofindex
;template struct typeofindex<0, _typelist>
;
非常優雅的完成了型別任務,以後只要寫typeofindex::value_type 就可以了。
task3: 獲取值的get函式如何定義,如何實現?
這個問題折騰了猿猿一整天。先看看我的容器定義吧:
// generic of valuetable
template class valuetable/* : public valuetable>*/{};
// specific of valuetable
template <>
class valuetable<>{}; // boundry
// specific of valuetable
template <>
class valuetable>{};
// valuetable offers real value (at runtime)
template class valuetable> :
public valuetable::tail_typelist>
;
第乙個類是通式,沒啥東西,就是告訴編譯器:有這麼個東西叫valuetable,接收任何數量任何型別的引數的模板類。
第二和第三個是邊界,類似遞迴出口,不解釋。
第四個是真正的容器定義類,也是所有資料的儲存地點。
那麼,問題就來了:某個valuetable怎麼去獲取指定索引的值呢?
看看我們手頭有的東西:有個通過type_list和列索引轉換到指定列型別的」函式「,列索引colindex(編譯期知道),行索引(執行期知道)。那麼我們就通過這些來寫出函式宣告:
templatetypename typeofindex::value_type get(size_t keyindex) const;
注意這裡的輸入引數只有兩個: colindex和keyindex(可以看成rowindex,這裡命名成這個樣子是有其它用途)。
有關實現這個函式。如果傳入的colindex為0,那麼直接返回當前的m_val[keyindex]就可以;否則,就在父類中遞迴找colindex-1的值。
templatetypename typeofindex::value_type get(size_t keyindex) const
template<>
typename typeofindex<0, type_list>::value_type get(size_t keyindex) const
看上去很美好,貌似任務都完成了。g++ -std=c++11 -c valuetable.cpp 試試?
不好,編譯器報error!!難道是**寫錯了?如果是rtti**,寫錯了在編譯器也不知道,只有在執行時候才能看出些東西來。對於剛接觸generic programming的猿猿來說還真不敢保證一定是對的。於是各種排查問題……(一下省略500字)
終於在stackoverflow中找到了答案:原來在模板類中是不允許進行成員函式的特化的,因為編譯器並不知道到底要特化的是哪乙個model的成員函式。而且更加悲催的是vc程式猿編譯這些**居然可以通過!! 微軟又大坑了一把各位猿猿們啊!!
ok,原因找到了,那麼到底怎麼實現呢?萬能的stackoverflow告訴猿猿,可以採用函式過載的方法實現。寫兩個輔助函式,作為private函式就好了。當然,要過載就必須型別(簽名)不同,那就在內部再加上乙個identity型別標記好了。
// identity mark
template struct identity{};
public:
templatetypename typeofindex::value_type get(size_t keyindex) const
private:
// override function of get implement
templatetypename typeofindex::value_type get_aux(size_t keyindex, identity) const
// specific of gettypename typeofindex<0, type_list>::value_type get_aux(size_t keyindex, identity<0>) const
終於大功告成,編譯通過。執行結果猿猿還沒有測試。以上方法僅供參考。
C 中的模板(類模板 模板類 模板函式)
1 class 一般class用於定義類,在模板引入c 後,最初定義模板的方法為 template,這裡class關鍵字表明t是乙個型別 2 typename 為了避免class在這兩個地方的使用可能給人帶來混淆,所以引入了typename這個關鍵字,它的作用同class一樣表明後面的符號為乙個型別...
類模板,模板類和函式模板,模板函式
單整數類 雙整數類 所以c艹跟其他強型別語言為我們提供了乙個所謂模版功能 變數型別 整數 類模板的重點是模板。表示的是乙個模板,專門用於產生類的模子。例子 1 template 2 class vector 3 使用這個vector模板就可以產生很多的class 類 vector vector ve...
c 模板類如何定義模板成員函式
最近跟網上乙個解決乙個模板問題 其實他在用g 編譯器寫模板定義成員函式,我在vs 05的c 編譯器上寫,然後我測試模板的結果是 特例模板不可以在類外定義,不管是在標頭檔案還是cpp檔案都要報錯,然後跟他說讓他寫在類中 當時不知道他在用g 編譯器 於是悲劇的問題出來了 他那個老是報沒在未命名空間類域中...