簡單來說,這玩意就是在編譯期做原本運行期在做的事情,你完全可以不需要用到這個技巧而達到同樣的功能。 例如原本運行期的OO繼承是這樣寫:
class Base{ public: virtual void someMethod() = 0; };
class Derived : public Base{ public: virtual void someMethod() override{}; };
在運行期呼叫裡面的someMethod()的時候需要再去找v-table才有辦法定位置該方法。由於所有事情都在運行時期發生,所以會有一些cost存在(方法定位的時間以及儲存v-table的空間)。只要該類別任何一個方法宣告virtual就會建立出v-table。
而用template寫就變成:
template <class Derived> class Base{
void someMethod(){
static_cast<Derived*>(this)->someMethodImplement();
};
};
class Derived : Base<Derived>{
public:
void someMethodImplement(){};
};
上面這個方法是template metaprogramming的一種應用,全名叫CRTP(curiously recurring template pattern)
我們可以看到template的寫法把把v-table省略掉了,尋找Derived的動作被移到編譯期上執行,因此在運行期會省一些時間。只是缺點在於寫不好的話會造成code size膨脹到非常大,而且編譯速度也會變慢。
為什麼呢?這是因為編譯器會在編譯期幫你把code產生出來,自動產生的code越多,當然code size會越大,而且編譯也會變慢。 你能想像你編譯出來的exe或lib檔大小原本只需要幾KB,但卻膨脹到MB甚至幾GB嗎?
好啦,這裡的比喻可能有點誇張,但系統一大起來的話也不是沒有可能。所以寫這個要特別注意code bloat的問題。 其實template metaprogramming在標準庫裡面用的到處都是,要能夠駕馭這套工具其實不是很容易,而且學習門檻還蠻高的。
我自己也還在學習路上 : )
好處是學會這套的話,在設計高效率的系統上會很有幫助。
Leave a Reply