2015-04-27 45 views
2

我開始研究CRTP成語,我注意到GCC有一個fdevirtualize標誌,它應該允許在可能的vtable調用轉換爲直接調用時進行轉換。雖然CRTP可以與任何(C++兼容)編譯器一起使用,但是如果我只想使用gcc進行開發,是否可以避免使用CRTP習慣用法離開gcc進行虛擬化過程,或者在可能的情況下最好使用它,以便使用靜態多態性以避免虛函數調用?CRTP vs GCC中的虛擬化標誌

回答

4

根據編譯器是否嵌入你的東西,Devirtualization可能有用或不用。

請注意,CRTP通常用於實現mixin和模板方法模式,例如,像這樣:

template <typename T, typename Derived> 
class pointer_base { 
    const Derived& self() const { return static_cast<const Derived&>(*this); } 
public: 
    T& operator *() const { return *self().get(); } 
    T* operator ->() const { return self().get(); } 
}; 

template <typename T> 
class smart_pointer : public pointer_base<T, smart_pointer<T>> { 
public: 
    T* get() const; 
}; 

和虛擬呼叫形式:在任何情況下

template <typename T> 
class pointer_base { 
protected: 
    ~pointer_base() = default; 
public: 
    virtual T* get() const = 0; 
    T& operator *() const { return *get(); } 
    T* operator ->() const { return get(); } 
}; 

template <typename T> 
class smart_pointer : public pointer_base<T> { 
public: 
    T* get() const override; 
}; 

用法

smart_pointer<int> p(new int); 
*p = 42; 

注意,可能有多個不同的智能指針類。在虛函數版本中,它們都來自相同的pointer_base。這意味着所有這些基礎函數都有一個版本可以共享。如果是這種情況,虛擬化就無法工作。

如果有問題的內聯函數到調用它只會工作,因爲那麼編譯器可以將代碼專注於特定的具體的智能指針類型。

當然,如果幫手很小,他們內聯的機率很高。另一方面,您現在擁有一個客戶端可以使用的pointer_base類。你可以從基地私人派生,但是你必須爲每個派生類中要公開的所有成員添加聲明。像pointers_base這樣的類包含很多(我的情況是2,但實際上應該有一個布爾轉換)小函數,這很煩人。但是,CRTP的語法混亂也是如此。我認爲,這歸結爲一個品味問題。

當你只有一個大模板方法時,編譯器不會內聯它。在這種情況下,它不能虛擬化。但CRTP有其自身的缺點:無論您是否需要,該方法都會重複用於每個基本實例。這可能導致代碼膨脹。

所以最終歸結爲模板VS虛函數通常的問題:與其相關的代碼尺寸的增加,或虛擬調用的性能損失,他們豎起了內聯屏障的專業代碼。

+0

很好的解釋,謝謝。 – Jepessen