2009-10-01 118 views
23

是否可以專門化模板類的特定成員?例如:特定成員的模板專業化?

template <typename T,bool B> 
struct X 
{ 
    void Specialized(); 
}; 

template <typename T> 
void X<T,true>::Specialized() 
{ 
    ... 
} 

template <typename T> 
void X<T,false>::Specialized() 
{ 
    ... 
} 

Of course,this code is not valid。

+0

這裏並不完全清楚你的意思。你的意思是強制模板參數是某種類型的後代?像你可以在Java中使用? – 2009-10-01 01:07:06

+1

@Alcon當專門研究模板類時,他必須爲整個類提供*不同的實現。在我看來,他想分享專業之間的通用代碼,除了少數功能。 – AraK 2009-10-01 01:15:19

+0

這個問題應該說「成員函數」而不是「成員」?爲了沒有人認爲這是關於數據成員。 – 2015-08-18 16:35:33

回答

3

這是我想出了,沒有那麼糟:)

//The generic template is by default 'flag == false' 
template <class Type, bool flag> 
struct something 
{ 
    void doSomething() 
    { 
     std::cout << "something. flag == false"; 
    } 
}; 

template <class Type> 
struct something<Type, true> : public something<Type, false> 
{ 
    void doSomething() // override original dosomething! 
    { 
     std::cout << "something. flag == true"; 
    } 
}; 

int main() 
{ 
    something<int, false> falseSomething; 
    something<int, true> trueSomething; 

    falseSomething.doSomething(); 
    trueSomething.doSomething(); 
} 
+5

你不是壓倒一切,你只是躲藏起來。 – curiousguy 2011-10-26 23:03:27

26

你只能通過提供所有模板參數專門它明確。類模板的成員函數不允許部分專業化。

template <typename T,bool B> 
struct X 
{ 
    void Specialized(); 
}; 

// works 
template <> 
void X<int,true>::Specialized() 
{ 
    ... 
} 

一個解決辦法是引進重載函數,這在同級別仍然受益,所以他們不得不成員變量,函數相同的訪問,配件

// "maps" a bool value to a struct type 
template<bool B> struct i2t { }; 

template <typename T,bool B> 
struct X 
{ 
    void Specialized() { SpecializedImpl(i2t<B>()); } 

private: 
    void SpecializedImpl(i2t<true>) { 
     // ... 
    } 

    void SpecializedImpl(i2t<false>) { 
     // ... 
    } 
}; 

注通過傳遞重載函數並將模板參數推入函數參數中,您可以任意「專門化」您的函數,也可以根據需要對它們進行模板化。另一種常見的方法是推遲到單獨定義

template<typename T, bool B> 
struct SpecializedImpl; 

template<typename T> 
struct SpecializedImpl<T, true> { 
    static void call() { 
    // ... 
    } 
}; 

template<typename T> 
struct SpecializedImpl<T, false> { 
    static void call() { 
    // ... 
    } 
}; 

template <typename T,bool B> 
struct X 
{ 
    void Specialized() { SpecializedImpl<T, B>::call(); } 
}; 

我發現,通常需要更多的代碼,我找到函數重載就好辦了類模板,而其他人則傾向於將延遲到類模板的方式。最後,這是一個品味問題。在這種情況下,您可以將X中的其他模板作爲嵌套模板來使用 - 在其他情況下,如果您明確地專門化而不是部分地進行專門化,那麼您不能這樣做,因爲您只能在命名空間範圍內放置明確的特化,不屬於課堂範圍。

您也可以創建一個僅用於功能重載的模板(它的作用類似於我們之前的i2t),因爲以下變體演示了哪個也會留下第一個參數變量(因此您可以將其與其他參數類型 - 不只是當前實例化的模板參數)

template <typename T,bool B> 
struct X 
{ 
private: 
    // maps a type and non-type parameter to a struct type 
    template<typename T, bool B> 
    struct SpecializedImpl { }; 

public: 
    void Specialized() { Specialized(SpecializedImpl<T, B>()); } 

private: 
    template<typename U> 
    void Specialized(SpecializedImpl<U, true>) { 
     // ... 
    } 

    template<typename U> 
    void Specialized(SpecializedImpl<U, false>) { 
     // ... 
    } 
}; 

我有時覺得,推遲到另一個模板是更好的(當涉及到此類案件的數組和指針,超載可以棘手,只是轉發給類模板對我來說一直比較容易),有時候只是在模板內重載會更好 - 尤其是如果你真的喜歡病房函數的參數,如果你觸摸類的成員變量。

+0

+1在我眼前的優雅的解決方案。 – AraK 2009-10-01 01:23:58

+0

感謝,讚賞:) – 2009-10-01 01:26:03

+0

現在,C++ 11出來了,這應該使用'std :: integral_constant'我認爲。將編輯我自己,但它在iPod Touch上的移動視圖中是一個真正的麻煩...... – Xeo 2011-10-25 19:18:11