2010-04-11 67 views
4

由於以下代碼中的函數模板是類模板的成員,因此如果不專門研究封閉類,則不能進行專門化。這是否完全模仿功能模板專業化?

但是,如果編譯器的完全優化開啓(假設Visual Studio 2010),下面代碼中的if-else語句是否會被優化?如果是這樣,這是不是意味着,對於所有實際目的而言,這是一個功能模板專業化而沒有任何性能成本?

template<typename T> 
struct Holder 
{ 
    T data; 

    template<int Number> 
    void saveReciprocalOf(); 
}; 

template<typename T> 
template<int Number> 
void Holder<T>::saveReciprocalOf() 
{ 
    //Will this if-else-statement get completely optimized out 
    if(Number == 0)  data = (T)0; 
    else    data = (T)1/Number; 
} 

//----------------------------------- 
void main() 
{ 
    Holder<float> holder; 
    holder.saveReciprocalOf<2>(); 
    cout << holder.data << endl; 
} 

回答

3

很可能會優化它。但是,如果你想成爲當然,你可以使用編譯時間if通過使用模板,例如。 Boost的MPL if_實現。

或者您可以使用SFINAE(Boost.enable_if)。

1

通常解決這類問題的方法是通過超載

template<typename T> 
struct Outer { 
    template<int I> 
    void inner() { 
    inner(int_<I>()); 
    } 

private: 
    template<int I> 
    struct int_ { }; 

    void inner(int_<0>) { 
    // for I == 0 
    } 

    template<int I> 
    void inner(int_<I>) { 
    // for others... 
    } 
}; 

這模仿明確的專業化相當不錯,甚至在情況下工作,其中用於其他路徑類型檢查會發瘋(不像if解決方案)

// ... 
    template<int I> 
    void inner(int_<I>) { 
    int tmp[I]; 
    } 
// ... 

這是有效的,因爲只有在I != 0這條路徑。現在你的情況,我首先想知道爲什麼你不只是傳遞一個正常的函數參數。你好像需要編譯時的性質I

// works just fine too in your example 
template<typename T> 
void Holder<T>::saveReciprocalOf(int Number) 
{ 
    // Will this if-else-statement get completely optimized out 
    if(Number == 0)  data = (T)0; 
    else    data = (T)1/Number; 
} 

如果編譯器內聯函數調用,這也有很好的機會被優化。在非嚴格需要的情況下使用模板非類型參數只會限制該函數的功能不能與運行時值一起使用。

+0

我發現當checked變量是編譯時間常量時,編譯器更有可能優化不必要的條件塊。但是,如果在使用常規函數參數時可能發生優化,那麼我認爲它沒有意義。 – zeroes00 2010-04-11 13:18:08

+0

@ Zeroes00我推薦先編譯,然後看看程序集,如果你真的認爲它可能會影響性能。下面是一個令人印象深刻的優化編譯器的例子:http://stackoverflow.com/questions/2419650/cc-macro-template-blackmagic-to-generate-unique-name/2419715#2419715 – 2010-04-11 13:24:53

0

謝謝。由於我想確定條件是最優化的(因爲它需要經常深入內部循環,並且我使用循環外部的開關盒來選擇正確的路徑),所以我最終可能會使用類似於enable_if_c的東西下面的代碼:

using boost::enable_if_c; 

template<typename T> 
struct Dummy 
{  
    template<int N> 
    typename enable_if_c<N==2,bool>::type    isPrimary() {return true;} 

    template<int N> 
    typename enable_if_c<N==3,bool>::type    isPrimary() {return true;} 

    template<int N> 
    typename enable_if_c<N==5,bool>::type    isPrimary() {return true;} 

    template<int N> 
    typename enable_if_c<N!=2&&N!=3&&N!=5,bool>::type isPrimary() {return false;} 
}; 

對我來說這似乎沒有Johannes的建議混亂。雖然最後(默認)的情況可能會變得很難看。

+0

我想這完全有可能計算一個值是否是模板元編程的主要元素(至少達到某些值 - 無論如何,它只能工作到最多6個值),因此根本沒有運行時函數調用。 – UncleBens 2010-04-11 13:47:13

+0

我實際上並不需要主數字或倒數,我只是用它們作爲示例來了解如何在類模板內專門化函數模板。 – zeroes00 2010-04-11 13:55:34

+0

也注意到'int_'也可以通過'boost'使用。它是'boost :: mpl :: int_'。 – 2010-04-11 14:43:46